比较sizeof(type)==常量时,C ++模板特化不起作用

时间:2016-09-24 18:40:49

标签: c++ templates c++11

#include <cstdint>
#include <iostream>

uint32_t ReadInt() { return 0; }
uint64_t ReadLong() { return 0; }

template<class SizeType>
class MyType
{
  public:
    SizeType Field;
    MyType()
    {
        Field = sizeof(SizeType) == 8 ? ReadLong() : ReadInt();
    }
};

int main()
{
    MyType<uint32_t> m;
    std::cout << m.Field;
}

我收到编译器警告,因为看起来条件sizeof(MyType)== 4在编译时没有被评估。

如果是,我们会专业化,这不会是一个问题。

无论如何我能做到这一点?

编辑: 想要实现的目标是:

        Field = ReadLong();

OR

        Field = ReadInt();

通过模板元编程。如果不专门阅读Read *功能,我可以这样做吗?考虑到c ++模板有多强大,我真的觉得我错过了一些时刻,因为如果我必须专注于Read *函数,兔子洞会继续深入。

3 个答案:

答案 0 :(得分:2)

warning C4244: '=': conversion from 'int64_t' to 'uint32_t', possible loss of data for the int specialization 
     

我收到编译器警告,因为看起来条件sizeof(MyType)== 4在编译时没有被评估。

不,它根本不是那样的。是否在编译时评估比较对条件表达式的返回类型没有影响。

如果我们通过删除条件简化示例并使用您使用的类型展开模板,我们可以获得最小的再现:

uint32_t Field;
int64_t temp = ReadInt(); // temporary variable for exposition
Field = temp;

显然,int64_t可能包含的值远远大于int32_t所代表的值。如果是,则转换中将丢失正确的值。编译器警告这种可能性。

为什么具体的条件int64_t的类型可能会问。那么,每个子表达式的类型分别是int64_tuint32_t,因此类型必须是其中之一。 Field的类型或比较结果 - 即使在编译时进行评估 - 对选择的类型没有影响。相反,在这种情况下使用integral promotion规则。

  

无论如何我能做到这一点?

模板功能应该有效:

template<class T>
T Read() {
    static_assert(false, "not implemented");
}

template<>
uint64_t Read<uint64_t>() {
    return ReadLong();
}

template<>
uint32_t Read<uint32_t>() {
    return ReadInt();
}

// ...
Field = Read<SizeType>();

答案 1 :(得分:1)

  

我收到编译器警告,因为看起来条件sizeof(MyType)== 4在编译时没有被评估

错误,它在编译时进行评估,但条件运算符仍然具有更大的结果类型的参数。

要修复它,只需添加一个演员:

Field = sizeof(SizeType) == 8 ? (SizeType)ReadLong() : ReadInt();

使用重载解析的另一种方法:

long ReadData(long) { return ReadLong(); }
int ReadData(int) { return ReadInt(); }
Field = ReadData(SizeType());

答案 2 :(得分:0)

条件运算符?:表达式求值为单个类型,它适用于可能的内部到构造结果类型。

即使在编译时对其进行评估,也会发生这种情况。

您的案例中的常见类型是两种可能的整数类型中最大的一种。