Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如果模板中的参数创建模板重新定义错误,则启用_C++_Templates_Typename_Redefinition_Enable If - Fatal编程技术网

C++ 如果模板中的参数创建模板重新定义错误,则启用

C++ 如果模板中的参数创建模板重新定义错误,则启用,c++,templates,typename,redefinition,enable-if,C++,Templates,Typename,Redefinition,Enable If,我真正想做的是在我的模板参数中定义一个typename,它可以在cast和return中使用 因此: template <typename T> typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type caster(T value){ return reinterpret_cast<unsigned char&>(value); } 模板 typ

我真正想做的是在我的模板参数中定义一个
typename
,它可以在cast和return中使用

因此:

template <typename T>
typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type caster(T value){ return reinterpret_cast<unsigned char&>(value); }
模板
typename std::enable_if::type caster(T值){return reinterpret_cast(值);}
将变成这样:

template <typename T, typename R = std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type >
R caster(T value){ return reinterpret_cast<R&>(value); }
模板
R caster(T值){return reinterpret_cast(值);}
这可以按照单个模板专门化的要求工作和行为,但我可以添加另一个专门化:

template <typename T, typename R = std::enable_if<sizeof(short) == sizeof(T), short>::type>
R caster(T value){ return reinterpret_cast<R&>(value); }
模板
R caster(T值){return reinterpret_cast(值);}
现在我得到一个错误:

错误C2995:'R caster(T)':已定义函数模板


有没有办法让编译器相信,对于任何给定的调用,实际上只会生成这些专门化中的一个?

没有。模板默认参数就是默认值。任何用户都可以调用
caster
,这将匹配两个重载

template <std::size_t N>
struct cast_result;

template <>
struct cast_result<sizeof(std::uint8_t)> {
  typedef std::uint8_t type;
};

template <>
struct cast_result<sizeof(std::uint16_t)> {
  typedef std::uint16_t type;
};

...

template <typename T, typename R = typename cast_result<sizeof(T)>::type>
R caster(T value) {
  return reinterpret_cast<R&>(value);
}
但是,可以添加更多的伪参数

template <typename T,
          typename R = typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type >
R caster(T value) { return reinterpret_cast<R&>(value); }

template <typename T,
          typename R = typename std::enable_if<sizeof(short) == sizeof(T), short>::type,
          typename = void>
R caster(T value) { return reinterpret_cast<R&>(value); }
最后一点注意:这种使用
reinterpret\u cast
的行为违反了别名规则。但是,这很容易解决:

template <typename T, typename R = typename cast_result<sizeof(T)>::type>
R caster(T value) {
  R result;
  std::memcpy(&result, &value, sizeof result);
  return result;
}
模板
主销后倾角(T值){
R结果;
std::memcpy(&result,&value,sizeof result);
返回结果;
}

似乎这里最好的解决方案可能是使用大量的s,这将防止我不得不愚弄模板专门化:

template <typename T, typename R = std::conditional<sizeof(T) == sizeof(unsigned char),
                                                    unsigned char,
                                                    conditional<sizeof(T) == sizeof(unsigned short),
                                                                unsigned short,
                                                                conditional<sizeof(T) == sizeof(unsigned long),
                                                                            unsigned long,
                                                                            enable_if<sizeof(T) == sizeof(unsigned long long), unsigned long long>::type>::type>::type>::type>
R caster(T value){ return reinterpret_cast<R&>(value); }
模板
R caster(T值){return reinterpret_cast(值);}
我向读者道歉,因为这就像阅读嵌套的三元词典。然而,我目前还不知道一个更干净的方法来处理这个问题

遗憾的是,这仍然不能阻止用户通过提供自己的第二个模板参数(如所述)来践踏所有我的默认设置

编辑:


我问了另一个问题,这个问题有一个解决方案,它不需要在模板定义中放置
typename
,也不需要声明两次类型。

啊,至少我知道它为什么现在没有生成。似乎我可以设置一个
typedef
或不是用户参数的东西,但可以定义要使用的类型。我在
reinterpret\u cast
上没有看到任何错误?对我来说,它应该按原样工作,这当然是有道理的。如果比特数相同,那么将一个视为另一个就不会有问题了?@JonathanMee该语言本可以这样定义,但事实并非如此。该标准包含:“如果程序试图通过以下类型以外的glvalue访问对象的存储值,则行为未定义:”后面是不包含特定大小对象的任何注释的列表。一些编译器(如GCC)使用该规则积极优化代码,注意到例如给定
int*a
long*b
,存储到
*a
并从
*b
读取的代码,编译器可以重新排序访问,因为不允许指针指向同一对象。@JonathanMee如果您使用
gcc-O2-Wall
编译,您将得到一条警告:“取消引用类型双关指针将破坏严格的别名规则”。(注意:该警告通常被抑制,但不要被愚弄为导致该警告的代码没有别名冲突。)