类型定义应该依赖于模板参数

Type definition should be dependent on template parameters

给定一个模板 class A,我想根据 A 的模板参数 T_lhs 和 [=16 定义一个类型 T_res =]:

template< typename T_lhs, typename T_rhs >
class A
{
  // definition of T_res in case "T_lhs and T_rhs are both not primitive types"
  template< bool lhs_is_fundamental = std::is_fundamental<T_lhs>::value,
            bool rhs_is_fundamental = std::is_fundamental<T_rhs>::value,
            std::enable_if_t<( !lhs_is_fundamental && !rhs_is_fundamental )>* = nullptr >
  using T_res = decltype( std::declval<T_lhs>().cast_to_primitive() / std::declval<T_rhs>().cast_to_primitive() );

  // definition of T_res in case "T_lhs and/or T_rhs is a primitive type"
  template< bool lhs_is_fundamental = std::is_fundamental<T_lhs>::value,
            bool rhs_is_fundamental = std::is_fundamental<T_rhs>::value,
            std::enable_if_t<( lhs_is_fundamental || rhs_is_fundamental )>* = nullptr >
  using T_res = decltype( std::declval<T_lhs>() / std::declval<T_rhs>() );

  // ...
};

在第一种情况下,T_lhsT_rhs 都不是原始类型,我的代码是这样设计的,它们表示 classes 实现了一个函数 cast_to_primitive()returns 原始类型;在第一种情况下,我希望 T_res 具有通过将 decltype( std::declval<T_lhs>().cast_to_primitive() ) 类型的元素除以 decltype( std::declval<T_rhs>().cast_to_primitive() ).

类型的元素而获得的类型

在第二种情况下,T_lhsT_rhs 是原始类型(或什至两者都是),我希望 T_res 具有通过划分元素获得的类型T_lhs 类型的 T_rhs 类型的元素。例如,如果 T_lhs 是原始类型,我的代码设计为 T_rhs 可以隐式转换为 T_lhs 类型的元素;这同样适用于 T_rhs 是原始的情况。

不幸的是,上面的代码无法编译。错误:

error: template non-type parameter has a different type 'std::enable_if_t<(lhs_is_fundamental || rhs_is_fundamental)> *' (aka 'typename enable_if<(lhs_is_fundamental || rhs_is_fundamental), void>::type *') in template redeclaration
            std::enable_if_t<( lhs_is_fundamental || rhs_is_fundamental )>* = nullptr >
                                                                            ^
note: previous non-type template parameter with type 'std::enable_if_t<(!lhs_is_fundamental && !rhs_is_fundamental)> *' (aka 'typename enable_if<(!lhs_is_fundamental && !rhs_is_fundamental), void>::type *') is here
            std::enable_if_t<( !lhs_is_fundamental && !rhs_is_fundamental )>* = nullptr >
                                                                              ^

有人可以帮我解决这个问题吗?

这与

中发现的问题大致相同

解决方案是使用 std::conditional 和辅助程序 类 来延迟 division/call 到 cast_to_primitive 的实例化,直到实例化 std::conditional 之后:

#include <type_traits>

template<class T1, class T2>
struct A
{
  template<class T=T1, class U=T2>
  struct cast_to_primitive_t {using type=decltype(std::declval<T>().cast_to_primitive() / std::declval<U>().cast_to_primitive());};
  template<class T=T1, class U=T2>
  struct primitive_div_t {using type=decltype(std::declval<T>() / std::declval<U>());};

  using T_res = typename std::conditional_t<std::is_fundamental<T1>{} && std::is_fundamental<T2>{}, primitive_div_t<>, cast_to_primitive_t<>>::type;
};