gpt4 book ai didi

c++ - 如何为相同类型的 typedef 提供模板特化?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:24:30 25 4
gpt4 key购买 nike

第 3 方 SDK 定义了几个 typedef,例如:

typedef unsigned char SDK_BYTE
typedef double SDK_DOUBLE
typedef unsigned char SDK_BOOLEAN

它还定义了一个变体类型SdkVariant:

class SdkVariant
{
public:
enum SdkType { SdkByte, SdkDouble, SdkBoolean };
bool toByte(SDK_BYTE&);
bool toDouble(SDK_DOUBLE&);
bool toBool(SDK_BOOLEAN&);
SdkType type();
};

从这样的变体中检索值看起来像这样(假设,我们知道所包含值的类型):

SdkVariant variant(foobar());
double value;
bool res = variant.toDouble(value);
if (!res)
diePainfully();
else
doSomethingWith(value);

这非常冗长,因此我想提供一个可以执行值检索和错误处理的 variant_cast-function-class:

// general interface:
template<class T>
class variant_cast
{
public:
T operator()(const SdkVariant& variant);
};

// template specializations:
template<>
SDK_DOUBLE variant_cast<SDK_DOUBLE>::operator()(const SdkVariant& variant)
{
SDK_DOUBLE value;
bool res = variant.toDouble(value);
if (!res)
diePainfully();
return value;
}

template<>
SDK_BYTE variant_cast<SDK_BYTE>::operator()(const SdkVariant& variant)
{
SDK_BYTE value;
bool res = variant.toByte(value);
if (!res)
diePainfully();
return value;
}

template<>
SDK_BOOLEAN variant_cast<SDK_BOOLEAN>::operator()(const SdkVariant& variant)
{
SDK_BOOLEAN value;
bool res = variant.toByte(value);
if (!res)
diePainfully();
return value;
}

这不会编译(C2995:函数模板已定义),因为 SDK_BYTE 和 SDK_BOOLEAN 是相同的类型(unsigned char)。我现在的想法是让预处理器检查 SDK_BYTE 和 SDK_BOOLEAN 是否相同,如果是,则为两者定义一个模板特化。如果它们不同,它应该使用上面的两个独立的特化。像这样:

#if SDK_BYTE == SDK_BOOLEAN
template<>
SDK_BYTE variant_cast<SDK_BYTE>::operator()(const SdkVariant& variant)
{
SDK_BYTE value;
bool res;
if (variant.type() == SdkByte)
res = variant.toByte(value);
else
res = variant.toBool(value);
if (!res)
diePainfully();
return value;
}
#else
// code from above
#endif

上述代码的问题在于,预处理器似乎无法解析这两个 typedef。有没有办法在预处理期间(正确地)比较两个 typedef?如果不是,是否有办法阻止编译器解析 typedef,以便它接受 SDK_BYTE 和 SDK_BOOLEAN 的两种不同的模板特化?如果不是,我仍然可以提供单一模板特化并使用 BOOST_STATIC_ASSERT 使编译器在 SDK_BYTE 和 SDK_BOOLEAN 不相等时失败,但是有没有更好的方法来解决我的问题?

最佳答案

如果 C++11 适合您,这里有一些代码说明了使用 std::enable_if 的可能解决方案和 std::is_same :

#include <iostream>
#include <type_traits>

struct SdkVariant
{
};

typedef int type1;
typedef float type2;

template <typename T, typename Enable=void>
class variant_cast
{
public:
/* Default implementation of the converter. This is undefined, but
you can define it to throw an exception instead. */
T operator()(const SdkVariant &v);
};

/* Conversion for type1. */
template <typename T>
class variant_cast<T,typename std::enable_if<std::is_same<T,type1>::value>::type>
{
public:
type1 operator()(const SdkVariant &v)
{
return type1 { 0 };
}
};

/* Conversion for type2, IF type2 != type1. Otherwise this
specialization will never be used. */
template <typename T>
class variant_cast<T,typename std::enable_if<
std::is_same<T,type2>::value
&& !std::is_same<type1,type2>::value>::type>
{
public:
type2 operator()(const SdkVariant &v)
{
return type2 { 1 };
}
};

int main()
{
variant_cast<type1> vc1;
variant_cast<type2> vc2;
std::cout << vc1({}) << std::endl;
std::cout << vc2({}) << std::endl;
return 0;
}

一些注意事项:

  1. 我只定义了type1,而不是该库定义的各种类型。和 type2
  2. 我定义了一个空的SdkVariant构造为虚拟
  3. 因为那个虚拟对象是空的,所以我的转换并没有真正转换任何东西。转换为 type1 时它只输出一个常量(值 0) , 和转换为 type2 时的常量(值 1) (如果 type2 实际上不同于 type1 )。
  4. 要测试它是否满足您的需要,您可以替换 type2 的定义与

    typedef int type2;

    因此它与 type1 的定义相同.它仍然会编译,并且不会出现与任何双重定义相关的错误。

  5. 我已经使用 GCC 4.7.0 和 --std=c++11 对此进行了测试选项。

关于使用std::enable_if的备注以及部分与显式模板特化

type1 的转换器声明为

template <typename T>
variant_cast<T,typename std::enable_if<std::is_same<T,type1>::value>::type>

这意味着它是为任何类型定义的T这与 type1 相同。相反,我们可以使用显式特化

template <>
variant_cast<type1>

这要简单得多,而且也有效

我没有这样做的唯一原因是 type2 的情况下它不会工作,因为对于type2我们必须检查它是否与type1相同,即我们必须使用 std::enable_if :

template <>
class variant_cast<type2,
typename std::enable_if<!std::is_same<type1,type2>::value>::type>

很遗憾,您不能使用 std::enable_if在显式特化中,因为显式特化不是模板——它是真正的数据类型,编译器必须处理它。如果type1type2是相同的,这个:

typename std::enable_if<!std::is_same<type1,type2>::value>::type

不存在,因为方式std::enable_if作品。所以编译失败,因为它不能实例化这个数据类型。

通过为任何类型定义转换器 T这与 type2 相同 我们避免了 type2 的显式实例化,因此我们不强制编译器处理它。它只会处理 type2 的模板特化如果std::enable_if<...>::type实际存在。否则它会简单地忽略它,这正是我们想要的。

同样,在 type1 的情况下(以及任何进一步的 type3type4 等)显式实例化将起作用。

我认为值得指出的是,为任何类型定义模板特化T这与某种类型相同 type 是一个普遍适用的技巧,当您出于正式原因不能使用显式特化时,因此您使用了部分特化,但您真的只想将它绑定(bind)到这种类型.例如,成员模板不能被显式实例化,除非它的封闭模板也被显式实例化。使用 std::enable_if 的组合和 std::is_same可能也有帮助。

关于c++ - 如何为相同类型的 typedef 提供模板特化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11982012/

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