有迹象表明,我编写了2个SFINAE片段。 他们做同样的事情。 然而,第一个作品,而第二个则没有。 为什么? (第二更接近我的真正的程序。)
此代码的工作(http://coliru.stacked-crooked.com/a/50e07af54708f076)
#include <iostream>
#include <type_traits>
enum EN{ EN1,EN2 };
template<EN T1> class B{
public: template<EN enLocal=T1> typename
std::enable_if<enLocal==EN1,void>::type test(){ std::cout<<"1"<<std::endl;}
public: template<EN enLocal=T1> typename
std::enable_if<enLocal==EN2,void>::type test(){ std::cout<<"2"<<std::endl; }
};
int main(){
B<EN1> b;
b.test();
}
但是这个代码是不可编译(http://coliru.stacked-crooked.com/a/28b6afd443b36c7e): -
#include <iostream>
#include <type_traits>
enum EN{ EN1,EN2 };
class Base{
public: void test(){
std::cout<<"1"<<std::endl;
};
};
template<EN T1> class B : public Base{
public: template<EN enLocal=T1>
std::enable_if_t< enLocal==EN2,void > test(){
std::cout<<"2"<<std::endl;
}
};
int main(){
B<EN1> bEn1; bEn1.test(); //should print 1
//B<EN2> bEn2; bEn2.test(); //print 2
}
我很新的SFINAE并通过https://stackoverflow.com/a/50562202/仍然在学习它。
这段代码有两个问题:
bEn1.test();
或bEn2.test();
编译器会找出名称test
是指在课堂B
功能和设定的重载函数将只包括B::test
。这可以通过固定从基类到派生类盐渍名:template<EN T1> class B : public Base{
public: using Base::test;
enable_if
作品),所以B<EN2> bEn2; bEn2.test();
将打印1是首选。为了再次使这项工作,你可以在从基类,而不是把Base::test
名称为派生类中调用函数的第一个例子介绍而又相似的另一重载之一:
public: template<EN enLocal=T1>
std::enable_if_t< enLocal!=EN2,void > test(){
return Base::test();
}
另一种可能的C ++ 17式解决方法利用代替型性状或SFINAE if constexpr
:
public: template<EN enLocal = T1> void
test()
{
if constexpr(EN2 == enLocal)
{
std::cout<<"2"<<std::endl;
}
else
{
Base::test();
}
}
根据什么是真正的使用情况,您也可以考虑某种形式的标签调度的:
enum class En {
base, a, b, c
};
template<En Type> void test_impl()
{
if constexpr (Type == En::base)
std::cout << "Base\n";
else if constexpr (Type == En::a)
std::cout << "1\n";
else if constexpr (Type == En::b)
std::cout << "2\n";
else
std::cout << "Default\n";
}
struct Base {
void test() {
std::cout << "Base - ";
test_impl<En::base>();
}
};
template<En Type>
struct Derived : public Base {
void test() {
std::cout << "Derived - ";
test_impl<Type>();
}
};
int main()
{
Base b;
b.test(); // -> "Base - Base"
Derived<En::a> b1;
b1.test(); // -> "Derived - 1"
Derived<En::b> b2;
b2.test(); // -> "Derived - 2"
Derived<En::base> b3;
b3.test(); // -> "Derived - Base"
Derived<En::c> b4;
b4.test(); // -> "Derived - Default"
}