Luk*_*rth 14 c++ templates sfinae variadic-templates c++11
我正在尝试使用std::enable_if
和SFINAE完全基于类的模板参数来切换类模板的方法的实现.例:
#include <type_traits>
template<class T1, class T2>
class Foo {
template<class InnerT, class ... Args>
typename std::enable_if<std::is_same<T1, T2>::value, void>::type
bar(InnerT param) {};
template<class InnerT, class ... Args>
typename std::enable_if<!std::is_same<T1, T2>::value, void>::type
bar(InnerT param) {};
};
int main() {
Foo<int, int> f;
}
Run Code Online (Sandbox Code Playgroud)
在这里,bar()
应该表现不同根据是否T1
与T2
属于同一类型或不.但是,此代码无法编译.GCC和clang都没有告诉我任何有用的东西.我怀疑问题是std::enable_if
条件不依赖于参数bar()
,即不依赖于标准第17.8.2点第8点规定的直接上下文.
这个代码很好地支持了这个假设:
#include <type_traits>
class DummyClass {};
template<class T1, class T2>
class Foo {
template<class InnerT, class ... Args>
typename std::enable_if<std::is_same<T1, T2>::value ||
std::is_same<InnerT, DummyClass>::value, void>::type
bar(InnerT param) {};
template<class InnerT, class ... Args>
typename std::enable_if<!std::is_same<T1, T2>::value ||
std::is_same<InnerT, DummyClass>::value, void>::type
bar(InnerT param) {};
};
int main() {
Foo<int, int> f;
}
Run Code Online (Sandbox Code Playgroud)
现在里面的表达式std::enable_if
取决于"立即上下文",即InnerT
,即使表达式的那一部分总是求值为false
.
看起来我可以使用它作为一种解决方法,但这感觉真的很丑陋和丑陋.你如何"正确"解决这个问题?我的想法是添加一个额外的模板参数(调用它DummyType
)bar()
,默认为例如DummyType = T1
,然后检查std::is_same<DummyType, T2>
,但bar()
采用参数包的事实使这不可能(或者它...?)
Cal*_*eth 15
而不是尝试SFINAE进入两个实现,只需使用正常的重载分辨率.
#include <type_traits>
#include <iostream>
template<class T1, class T2>
class Foo {
template<class InnerT, class ... Args>
void do_bar(InnerT param, std::true_type, Args... args) { std::cout << "same" << std::endl; }
template<class InnerT, class ... Args>
void do_bar(InnerT param, std::false_type, Args... args) { std::cout << "not same" << std::endl; }
public:
template<class InnerT, class ... Args>
void bar(InnerT&& param, Args&&... args)
{
do_bar(std::forward<InnerT>(param), std::is_same<T1, T2>{}, std::forward<Args>(args)...);
}
};
int main() {
Foo<int, int> f1;
Foo<int, double> f2;
f1.bar(1, 2, 3);
f2.bar("Hello");
}
Run Code Online (Sandbox Code Playgroud)
小智 7
要从评论中扩展:
我的想法是添加一个额外的模板参数(调用它
DummyType
)bar()
,默认为例如DummyType = T1
,然后检查std::is_same<DummyType, T2>
,但bar()
采用参数包的事实使这不可能(或者它...?)
它没有.完全按照你的想法行事是行不通的.
#include <type_traits>
template<class T1, class T2>
struct Foo {
template<class InnerT, class ... Args, class DummyType = T1>
typename std::enable_if<std::is_same<DummyType, T2>::value, void>::type
bar(InnerT param) {};
template<class InnerT, class ... Args, class DummyType = T1>
typename std::enable_if<!std::is_same<DummyType, T2>::value, void>::type
bar(InnerT param) {};
};
int main() {
Foo<int, int> f;
f.bar(3); // InnerT = int; Args = empty; DummyType = int.
f.bar<int, void, short>(4); // InnerT = int; Args = void, short; DummyType = int.
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我添加DummyType作为第二个模板参数,再后来通过的模板参数列表,应该进入的包 - 那第二个参数不应该去现在怎么做编译成DummyType,但要这部分的第一件事ARGS?
这就是我添加为最后一个参数的原因.如果模板包参数具有默认值,则允许它们遵循模板包参数.编译器将使用所有显式指定的参数Args
,并且DummyType = T1
无论您指定哪个参数都将使用.