模板参数中的enable_if创建模板重新定义错误

enable_if in template Parameters Creates Template Redefinition Error

本文关键字:新定义 定义 错误 建模 创建 参数 enable if      更新时间:2023-10-16

在这个答案中,我真正想做的是在我的模板参数中定义一个typename,它可以用于强制转换返回。

所以这个:

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

会变成这样:

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); }

这对于单个模板专业化来说是可以正常工作和行为的,但我需要添加另一个重载:

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

现在我得到一个错误:

错误C2995:"R caster(T)":已定义功能模板

有没有一种方法可以让编译器相信,对于任何给定的调用,这些专业化中只有一个会真正构建?

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

但是,可以添加更多的伪参数。

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); }

(还要注意添加的typename。)


然而,由于所有的身体都是一样的,我可能不会选择过载。

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);
}

最后要注意的是:reinterpret_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;
}

这里最好的解决方案可能是使用大量的conditional,这将防止我不得不篡改模板专业化:

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); }

我向读者道歉,因为这就像阅读嵌套的燕鸥。然而,我目前还不知道有什么更干净的方法来处理这个问题。

遗憾的是,这仍然不能阻止用户通过提供hvd提到的他自己的第二个模板参数来践踏我的所有默认值。

编辑:

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