C++ SFINAE和模板函数实例化:为什么在启用SFINAE类型的函数参数中使用模板参数时无法推导?
这几天我在用SFINAE做实验,有些事情让我困惑。为什么在C++ SFINAE和模板函数实例化:为什么在启用SFINAE类型的函数参数中使用模板参数时无法推导?,c++,templates,c++14,template-argument-deduction,C++,Templates,C++14,Template Argument Deduction,这几天我在用SFINAE做实验,有些事情让我困惑。为什么在my\u函数的实例化中不能推断my\u type\u a class my_type_a {}; template <typename T> class my_common_type { public: constexpr static const bool valid = false; }; template <> class my_common_type<my_type_a> { pub
my\u函数的实例化中不能推断my\u type\u a
class my_type_a {};
template <typename T>
class my_common_type {
public:
constexpr static const bool valid = false;
};
template <>
class my_common_type<my_type_a> {
public:
constexpr static const bool valid = true;
using type = my_type_a;
};
template <typename T> using my_common_type_t = typename my_common_type<T>::type;
template <typename T, typename V>
void my_function(my_common_type_t<T> my_cvalue, V my_value) {}
int main(void) {
my_function(my_type_a(), 1.0);
}
class my_type_a{};
模板
将my_分类为common_类型{
公众:
constexpr static const bool valid=false;
};
模板
将my_分类为common_类型{
公众:
constexpr static const bool valid=true;
使用类型=我的类型;
};
使用my_common_type_t=typename my_common_type::type的模板;
模板
void my_函数(my_common_type_t my_cvalue,V my_value){}
内部主(空){
my_函数(my_type_a(),1.0);
}
G++给了我这个:
/home/flisboac/test-template-template-arg-subst.cpp: In function ‘int main()’:
/home/flisboac/test-template-template-arg-subst.cpp:21:30: error: no matching function for call to ‘my_function(my_type_a, double)’
my_function(my_type_a(), 1.0);
^
/home/flisboac/test-template-template-arg-subst.cpp:18:6: note: candidate: template<class T, class V> void my_function(my_common_type_t<T>, V)
void my_function(my_common_type_t<T> my_type, V my_value) {}
^~~~~~~~~~~
/home/flisboac/test-template-template-arg-subst.cpp:18:6: note: template argument deduction/substitution failed:
/home/flisboac/test-template-template-arg-subst.cpp:21:30: note: couldn't deduce template parameter ‘T’
my_function(my_type_a(), 1.0);
^
/home/flisboac/test-template-template-arg-subst.cpp:在函数“int main()”中:
/home/flisboac/test-template-template-arg-subst.cpp:21:30:错误:没有用于调用“my_函数(my_类型_a,double)”的匹配函数
my_函数(my_type_a(),1.0);
^
/home/flisboac/test-template-template-arg-subst.cpp:18:6:注:候选:模板void my_函数(my_common_type_t,V)
void my_函数(my_common_type_t my_type,V my_value){}
^~~~~~~~~~~
/home/flisboac/test-template-template-arg-subst.cpp:18:6:注意:模板参数推导/替换失败:
/home/flisboac/test-template-template-arg-subst.cpp:21:30:注意:无法推断模板参数“t”
my_函数(my_type_a(),1.0);
^
我所期望的是,当调用my_函数时,正如我在main
中所做的那样,T
将被推断为函数的第一个参数的类型,并且该类型将在函数的实例化中使用。但似乎my_common\u type\u t
在函数之前被实例化,但即便如此,my\u cvalue
的类型无论如何也会变成my\u type\u a
,所以我不明白为什么这不起作用
有没有其他方法可以做到这一点?我应该避免两个(或多个)模板间接级别吗? < P>,请考虑如下:
template <>
struct my_common_type<int> {
constexpr static const bool valid = true;
using type = my_type_a;
};
template <>
struct my_common_type<double> {
constexpr static const bool valid = true;
using type = my_type_a;
};
// ...
int main(void) {
my_function(my_type_a{}, 1.0);
}
T
推导出的是什么<代码>整数
,简单!编译器对这种匹配感到满意。另外,由于test\u t
不能专门化,test\u t
只被认为是某物
此外,这也适用于多个级别的别名:
template<typename T>
using test_t = T;
template<typename T>
using test2_t = test_t<T>;
template<typename T>
void call(test2_t<T>) {}
int main() {
call(1); // will also work
}
请注意,这也是可行的:
template <typename T>
using my_common_type_t = first_t<T, std::enable_if_t<my_common_type<T>::valid>>;
模板
使用my_common_type_t=第一个\u t;
现在扣款将如期发生
注意,这个技巧只适用于C++14,因为在这种情况下,sfinae(删除的参数)只保证在C++14之后发生
还注意到,您应该使用<代码>结构> <代码>,或者使用<代码>公用:使成员<代码> MyAuxMuyLyType::类型< /代码> Pube,否则GCC将输出伪造错误。
< P>:请考虑:
template <>
struct my_common_type<int> {
constexpr static const bool valid = true;
using type = my_type_a;
};
template <>
struct my_common_type<double> {
constexpr static const bool valid = true;
using type = my_type_a;
};
// ...
int main(void) {
my_function(my_type_a{}, 1.0);
}
T
推导出的是什么<代码>整数
,简单!编译器对这种匹配感到满意。另外,由于test\u t
不能专门化,test\u t
只被认为是某物
此外,这也适用于多个级别的别名:
template<typename T>
using test_t = T;
template<typename T>
using test2_t = test_t<T>;
template<typename T>
void call(test2_t<T>) {}
int main() {
call(1); // will also work
}
请注意,这也是可行的:
template <typename T>
using my_common_type_t = first_t<T, std::enable_if_t<my_common_type<T>::valid>>;
模板
使用my_common_type_t=第一个\u t;
现在扣款将如期发生
注意,这个技巧只适用于C++14,因为在这种情况下,sfinae(删除的参数)只保证在C++14之后发生
还要注意的是,您应该为您的trait使用struct
,或者使用public:
将成员my_common_type::type
公开,否则GCC将输出一个伪错误。在my_common_type::type
中,T
位于。您希望编译器用每种可能的类型T
实例化my_common_type
,希望对于其中一种类型,my_common_type::type
与my_type_a
兼容;或者从事定理证明练习,试图从分析的角度找到这样一种类型。编译器两者都没有。@Igor我知道规则1(来自您提供的链接)肯定与我的示例相匹配。然而,为什么不清楚T
不一定是my_type_a
?如果在实例化my\u函数
之前实例化了my\u common\u type
,则类型可能是my\u type\u a
或什么都不是(因此该函数将通过SFINAE消除)。如果它在期间或之后被实例化,编译器将把my_common_type
的信息作为候选(正因为如此,T=my_type\u a
),不是吗?“为什么不清楚”这是我所说的定理证明练习。“清楚”在这里的意思是“可以从现有事实中证明”。也许可以,但编译器不需要拥有这种推理引擎。我认为信息可以从调用站点获得。但也许我从错误的角度考虑问题。我想我理解这里的问题,但我很难想出一个明确的答案my_函数
在参数my_cvalue
中接收类型为my_common_type::type
的值,并且T
不在其他任何地方使用。我传递给函数的是一个值my\u type\u a
,这是具体的my_common_type::type
仍然未知,因为::type
依赖于模板替换,而模板替换又依赖于T
,这是未知的。在my_common_type::type
中,T
处于。您希望编译器用每种可能的类型T
实例化my_common_type
,希望对于其中一种类型,my_common_type::type
与my_type_a
兼容;或者从事