gpt4 book ai didi

c++ - 根据特征隐藏类模板实例

转载 作者:搜寻专家 更新时间:2023-10-31 02:06:53 25 4
gpt4 key购买 nike

我有一个如下所示的特征类,它反射(reflect)了两种类型之间的兼容性:

template <typename ObjectType, typename ArgumentType>
struct Traits
{
static const bool SpecialMethodAvailable = false;
};

单个成员确定 SpecialMethod() 是否可以在 ObjectType 类型的对象上调用 ArgumentType 类型的参数。

支持这个的简单类如下:

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 会产生编译错误:

In static member function ‘static void Worker::SpecialMethodAvailable>::type>::DoSomething(T, GlobalDataType&)’: source.cpp:38:15: error: request for member ‘SpecialMethod’ in ‘globalData’, which is of non-class type GlobalDataType {aka int}’

有人可以解释为什么这在 GCC 下无法正常工作吗?有什么替代方案?

Link to online compiler

最佳答案

正如 Jarod42 所解释的,这个方法

static void DoSomething(T t, GlobalDataType& globalData)
{
globalData.SpecialMethod(t);
}

GlobalDataType 固定为 int,永远是错误的(永远是 T 类型),因为它确定 int 没有 SpecialMethod()

要以最少的代码更改解决此问题,您可以模板化第二个参数

template <typename U>
static void DoSomething(T t, U & globalData)
{ globalData.SpecialMethod(t); }

如果您希望 DoSomething() 仅接收(作为第二个参数)GlobalDataType,您可以使用 SFINAE 强制启用 DoSomething,仅当 UGlobalDataType 时。作为

template <typename U>
static typename std::enable_if<std::is_same<U, GlobalDataType>{}>
DoSomething(T t, U & globalData)
{ globalData.SpecialMethod(t); }

What would be alternatives?

我向您推荐一种完全不同的方法,基于(遵循 std::declval() 示例)函数声明。

首先,几个模板辅助函数

template <typename ObjectType, typename ... Args>
constexpr auto withSpecialMethodHelper (int)
-> decltype(std::declval<ObjectType>.SpecialMethod(std::declval<Args>...),
std::true_type{} );

template <typename ... Args>
constexpr std::false_type withSpecialMethodHelper (long);

现在您可以编写一个模板函数的声明,如果 ObjectType 有一个 SpecialMethod() 可以是使用 Args...

类型的可变参数列表调用
template <typename ObjectType, typename ... Args>
constexpr auto withSpecialMethod ()
-> decltype( withSpecialMethodHelper<ObjectType, Args...>(0) );

或者可能更好,正如 Jarod42 所建议的,通过 using

template <typename ObjectType, typename ... Args>
using withSpecialMethod
= decltype( withSpecialMethodHelper<ObjectType, Args...>(0) );

如果可以使用C++14,还可以定义一个withSpecialMethod_v模板constexpr变量

template <typename ObjectType, typename ... Args>
constexpr bool withSpecialMethod_v
= decltype(withSpecialMethod<ObjectType, Args...>())::value;

在声明函数的情况下或

template <typename ObjectType, typename ... Args>
constexpr bool withSpecialMethod_v
= withSpecialMethod<ObjectType, Args...>::value;

使用的情况下,可以简化使用。

现在 Worker 类和特化变成了

template <typename T, bool = withSpecialMethod_v<GlobalDataType, T>>
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, true>
{
template <typename U>
static void DoSomething(T t, U & globalData)
{ globalData.SpecialMethod(t); }
};

关于c++ - 根据特征隐藏类模板实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49559750/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com