问题描述
当我编译此代码时:
#include <type_traits> template <typename T> void do_stuff(std::enable_if_t<std::is_integral<T>::value, T> &t) {} template <typename T> void do_stuff(std::enable_if_t<std::is_class<T>::value, T> &t) {} int main() { int i = 1; do_stuff(i); return 0; }
GCC说:
37325975.cpp: In function ‘int main()’: 37325975.cpp:11:15: error: no matching function for call to ‘do_stuff(int&)’ do_stuff(i); ^ 37325975.cpp:4:6: note: candidate: template<class T> void do_stuff(std::enable_if_t<std::is_integral<_Tp>::value, T>&) void do_stuff(std::enable_if_t<std::is_integral<T>::value, T> &t) {} ^ 37325975.cpp:4:6: note: template argument deduction/substitution failed: 37325975.cpp:11:15: note: couldn't deduce template parameter ‘T’ do_stuff(i); ^ 37325975.cpp:7:6: note: candidate: template<class T> void do_stuff(std::enable_if_t<std::is_class<T>::value, T>&) void do_stuff(std::enable_if_t<std::is_class<T>::value, T> &t) {} ^ 37325975.cpp:7:6: note: template argument deduction/substitution failed: 37325975.cpp:11:15: note: couldn't deduce template parameter ‘T’ do_stuff(i); ^
我还尝试了MSVC 2013.
为什么我会得到这些错误?
推荐答案
正如编译器所说,该参数类型是不可用的,因此您需要手动提供模板参数,例如:
do_stuff<int>(i);
一个更好的选择是将std::enable_if放在返回类型或模板参数列表中:
//Return type template <typename T> std::enable_if_t<std::is_integral<T>::value> do_stuff(T &t) {} template <typename T> std::enable_if_t<std::is_class<T>::value> do_stuff(T &t) {} //Parameter list template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr> void do_stuff(T &t) {} template <typename T, std::enable_if_t<std::is_class<T>::value>* = nullptr > void do_stuff(T &t) {}
这样仍然可以推导模板参数:
do_stuff(i);
其他推荐答案
为什么我会得到这些错误?
由于nested-name-specifier的模板参数扣除失败,因此是非卵子上下文.
Nested-Name Pesifier(示波器分辨率运算符的所有内容::)使用合格的ID指定的类型.
// the identity template, often used to exclude specific arguments from deduction template<typename T> struct identity { typedef T type; }; template<typename T> void bad(std::vector<T> x, T value = 1); template<typename T> void good(std::vector<T> x, typename identity<T>::type value = 1); std::vector<std::complex<double>> x; bad(x, 1.2); // P1 = std::vector<T>, A1 = std::vector<std::complex<double>> // P1/A1: deduced T = std::complex<double> // P2 = T, A2 = double // P2/A2: deduced T = double // error: deduction fails, T is ambiguous good(x, 1.2); // P1 = std::vector<T>, A1 = std::vector<std::complex<double>> // P1/A1: deduced T = std::complex<double> // P2 = identity<T>::type, A2 = double // P2/A2: uses T deduced by P1/A1 because T is to the left of :: in P2 // OK: T = std::complex<double>
其他推荐答案
编译器尝试解决do_stuff(int&)时,它看到编译器告诉您的两个候选人.但是,找不到满足std::enable_if_t<std::is_integral<T>::value, T> == int的T,也无法找到满足std::enable_if_t<std::is_class<T>::value, T> == int的T.
如 tartanllama的答案,避免这种情况的方法是使参数可推论(例如do_stuff(T&)),并制作 return类型或a 后续模板参数依赖于T.
问题描述
When I compile this code:
#include <type_traits> template <typename T> void do_stuff(std::enable_if_t<std::is_integral<T>::value, T> &t) {} template <typename T> void do_stuff(std::enable_if_t<std::is_class<T>::value, T> &t) {} int main() { int i = 1; do_stuff(i); return 0; }
GCC says:
37325975.cpp: In function ‘int main()’: 37325975.cpp:11:15: error: no matching function for call to ‘do_stuff(int&)’ do_stuff(i); ^ 37325975.cpp:4:6: note: candidate: template<class T> void do_stuff(std::enable_if_t<std::is_integral<_Tp>::value, T>&) void do_stuff(std::enable_if_t<std::is_integral<T>::value, T> &t) {} ^ 37325975.cpp:4:6: note: template argument deduction/substitution failed: 37325975.cpp:11:15: note: couldn't deduce template parameter ‘T’ do_stuff(i); ^ 37325975.cpp:7:6: note: candidate: template<class T> void do_stuff(std::enable_if_t<std::is_class<T>::value, T>&) void do_stuff(std::enable_if_t<std::is_class<T>::value, T> &t) {} ^ 37325975.cpp:7:6: note: template argument deduction/substitution failed: 37325975.cpp:11:15: note: couldn't deduce template parameter ‘T’ do_stuff(i); ^
I've also tried on msvc 2013.
Why do I get these errors?
推荐答案
As the compiler says, that parameter type is non-deducible, so you would need to supply the template argument manually, like this:
do_stuff<int>(i);
A better option is to put the std::enable_if in the return type or template parameter list:
//Return type template <typename T> std::enable_if_t<std::is_integral<T>::value> do_stuff(T &t) {} template <typename T> std::enable_if_t<std::is_class<T>::value> do_stuff(T &t) {} //Parameter list template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr> void do_stuff(T &t) {} template <typename T, std::enable_if_t<std::is_class<T>::value>* = nullptr > void do_stuff(T &t) {}
This way the template parameter can still be deduced:
do_stuff(i);
其他推荐答案
Why do I get these errors?
Because template argument deduction fails for nested-name-specifier, which is non-deduced contexts.
The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id.
// the identity template, often used to exclude specific arguments from deduction template<typename T> struct identity { typedef T type; }; template<typename T> void bad(std::vector<T> x, T value = 1); template<typename T> void good(std::vector<T> x, typename identity<T>::type value = 1); std::vector<std::complex<double>> x; bad(x, 1.2); // P1 = std::vector<T>, A1 = std::vector<std::complex<double>> // P1/A1: deduced T = std::complex<double> // P2 = T, A2 = double // P2/A2: deduced T = double // error: deduction fails, T is ambiguous good(x, 1.2); // P1 = std::vector<T>, A1 = std::vector<std::complex<double>> // P1/A1: deduced T = std::complex<double> // P2 = identity<T>::type, A2 = double // P2/A2: uses T deduced by P1/A1 because T is to the left of :: in P2 // OK: T = std::complex<double>
其他推荐答案
When the compiler tries to resolve do_stuff(int&), it sees the two candidates that the compiler tells you about. But it's not able to "work backwards" to find a T that satisfies std::enable_if_t<std::is_integral<T>::value, T> == int, nor to find a T that satisfies std::enable_if_t<std::is_class<T>::value, T> == int.
As mentioned in TartanLlama's answer, the way to avoid this is to make the argument deducible (e.g. do_stuff(T&)) and make the return type or a subsequent template argument dependent on T.