【发布时间】:2018-09-08 15:05:33
【问题描述】:
我有一个类似下面的特征类,它反映了两种类型之间的兼容性:
template <typename ObjectType, typename ArgumentType>
struct Traits
{
static const bool SpecialMethodAvailable = false;
};
单个成员确定是否可以使用 ArgumentType 类型的参数对 ObjectType 类型的对象调用 SpecialMethod()。
一个支持这个的简单类如下:
class ClassWithSpecialMethod
{
public:
template <typename T>
void SpecialMethod(T param) { std::cout << "Special Method called with " << param << std::endl; }
};
template <typename ArgumentType>
struct Traits<ClassWithSpecialMethod, ArgumentType>
{
static const bool SpecialMethodAvailable = true;
};
我想编写一个使用这个特征类的工作类,并在它可用时调用特殊方法。基本上是这样的:
template <typename T>
struct Worker
{
static void DoSomething(T t, GlobalDataType& globalData)
{
//if Traits<GlobalDataType, T>::SpecialMethodAvailable
// call the method
//else
// do something different
}
};
我尝试使用std::enable_if 来实现这一点。我的解决方案适用于 Visual C 14.1 编译器,但不适用于 GCC。这是我尝试过的:
template <typename T, typename Enable = void>
struct Worker
{
static void DoSomething(T t, GlobalDataType& globalData)
{
std::cout << "There is no special method (called with " << t << ")" << std::endl;
}
};
template <typename T>
struct Worker<T, typename std::enable_if<Traits<GlobalDataType, T>::SpecialMethodAvailable>::type>
{
static void DoSomething(T t, GlobalDataType& globalData)
{
globalData.SpecialMethod(t);
}
};
我是这样使用的:
typedef ... GlobalDataType; //before the template declarations
int main()
{
GlobalDataType td;
int integer = 0;
Worker<int>::DoSomething(integer, td);
}
如果GlobalDataType 被定义为ClassWithSpecialMethod,VS 和 GCC 都可以正常编译并正确输出:
Special Method called with 0
但是,如果 GlobalDataType 被定义为不允许使用特殊方法的内容(例如 int),VS 仍然会产生正确的输出,而 GCC 会导致编译错误:
在静态成员函数‘static void Worker::SpecialMethodAvailable>::type>::DoSomething(T, GlobalDataType&)’中: source.cpp:38:15: 错误:请求“globalData”中的成员“SpecialMethod”,这是非类类型 GlobalDataType {aka int}'
有人可以解释为什么这在 GCC 下不能按预期工作吗?有什么替代方案?
【问题讨论】:
-
请注意,std::experimental::is_detected 用专业化替换你的特征:
template <typename T, typename Arg> using SpecialMethod_t = decltype(std::declval<T>().SpecialMethod(std::declval<Arg>()));然后template <typename T, typename Arg> using Traits = std::experimental::is_detected<SpecialMethod_t, T, Arg>;。 -
@Raxvan:即使您的解释错误/不准确,您的替代实现仍然有效。
-
@Raxvan - 我同意 Jarod42:我觉得你的解决方案很有趣。
标签: c++ c++11 templates gcc sfinae