下面的(简化)代码无法编译,因为编译器无法推导模板参数。
#include <iostream>
#include <utility>
#include <vector>
enum class animal : size_t { cat, dog };
template <animal a, class... U>
using animal_select_t = typename std::tuple_element<static_cast<size_t>(a), std::tuple<U...>>::type;
template <animal a>
using mytype = animal_select_t<a, int, double>;
template <animal a>
void print(std::vector<mytype<a>>&& vec)
{
for (const auto& x : vec)
std::cout << x << std::endl;
vec.resize(0);
}
int main()
{
std::vector<int> v(3, 1);
print(std::move(v));
std::cout << v.size() << std::endl;
return 0;
}
错误消息为
deduce.cpp: In function ‘int main()’:
deduce.cpp:24:8: error: no matching function for call to ‘print(std::remove_reference<std::vector<int>&>::type)’
24 | print(std::move(v));
| ~~~~~^~~~~~~~~~~~~~
deduce.cpp:14:6: note: candidate: ‘template<animal a> void print(std::vector<typename std::tuple_element<static_cast<long unsigned int>(a), std::tuple<int, double> >::type>&&)’
14 | void print(std::vector<mytype<a>>&& vec)
| ^~~~~
deduce.cpp:14:6: note: template argument deduction/substitution failed:
deduce.cpp:24:8: note: couldn’t deduce template parameter ‘a’
24 | print(std::move(v));
显然,这是一个nondeduced context的案例。
显然,减少模板参数的“嵌套”可以解决这个问题。例如,print
例程可以修改为
template <typename U>
void print(std::vector<U>&& vec)
{
// which animal?
for (const auto& x : vec)
std::cout << x << std::endl;
vec.resize(0);
}
然而,该解决方案不是最优的,因为
print
可以潜在地用std::vector
示例化,该类型不是mytype
中给出的选择之一- 在实际的代码中,我可能需要知道实际的模板参数
animal a
。
假设我们在第二个代码块中使用print
,那么如何:
- 将示例化限制为允许的类型
mytype<a>
,其中a
和animal
? - 推导模板参数
animal
?
或者有更好的解决方案,以不同的方式实现print
?
请注意,我正在寻找一个可扩展的解决方案。显然,对于上面的例子,解决方案很容易,只要考虑int
和double
。相反,我正在寻找一种解决方案,即使在enum class animal
和/或类型别名mytype
被更改时,我也可以通用。另外,我正在寻找C++17标准中的解决方案。
1条答案
按热度按时间qlvxas9a1#
如果你能在枚举中创建枚举数列表的参数包,你可以做各种各样的事情:
一旦你有了这个参数,你就可以解压缩参数包,并使用fold表达式来检查哪个
mytype
示例化对应于特定类型:您可以执行类似的操作,检查
mytype
的任何示例化是否具有特定类型(换句话说,如果T
在列表animal_select_t<a, int, double>
中)在static_assert中使用这个来限制可以传递给
print
的类型:Demo