模板元编程递归评估

Template metaprogramming recursive evaluation

template<typename T>
struct rm_const_volatile {
    using type = T;
};

// Call this (partial)specialization as "1"
template<typename T>
struct rm_const_volatile<const T> {
    // remove topmost const and recurse on T
    using type = typename rm_const_volatile<T>::type;
};

// Call this (partial)specialization as "2"
template<typename T>
struct rm_const_volatile<volatile T> {
    // remove topmost volatile and recurse on T
    using type = typename rm_const_volatile<T>::type;  
};

我已经像上面那样定义了 remove const volatile 限定符模板元程序。

逻辑上,当我写 rm_const_volatile<const volatile int> 时,我的期望是编译器将按以下顺序计算:

案例一:

案例二:

所以在我看来,上面的模板专业化和通用定义足以删除任何 const volatile 限定符。

将实际行为错误删除为模棱两可的模板实例化。

// In main() below two calls are present (refer cpp.sh link below mentioned for full code)

----
   std::cout << "Is volatile const int integral type with rm_const_volatile: " << is_integral<rm_const_volatile<volatile const int>::type>::value << std::endl;
   
   std::cout << "Is const volatile int integral type with rm_const_volatile: " << is_integral<rm_const_volatile<const volatile int>::type>::value << std::endl;

-------

 In function 'int main()':
54:132: error: ambiguous class template instantiation for 'struct rm_const_volatile<const volatile int>'
26:8: error: candidates are: struct rm_const_volatile<const T>
31:8: error:                 struct rm_const_volatile<volatile T>
54:95: error: incomplete type 'rm_const_volatile<const volatile int>' used in nested name specifier
54:95: error: incomplete type 'rm_const_volatile<const volatile int>' used in nested name specifier
54:138: error: template argument 1 is invalid

当我添加以下模板专业化时,一切正常。

template<typename T>
struct rm_const_volatile<const volatile T> {
    using type = T;  
};

完整代码请参考此link。

我想知道为什么编译器将模板实例化报告为不明确,而显然它可以切断最顶层的限定符并递归实例化为最终结果,正如我在上面的案例 1 和 2 中提到的那样。

非常感谢您的宝贵意见,并衷心感谢您的宝贵时间。

I would like to know why the compiler reports template instantiation as ambiguous

C++ 认为 const volatile intvolatile const int 是同一类型。它们可以互换并且意思相同

这种类型的一些其他拼写方式:

  • int const volatile
  • int volatile const
  • const int volatile
  • volatile int const

也就是说,C++ 永远不会根据您选择拼写特定类型的方式更改重载规则。

因此,模板特化 <const T><volatile T> 都同样专用于 <const volatile int>。两个限定词都不优先于另一个。