【问题标题】:Why is the template specialization not chosen?为什么没有选择模板专业化?
【发布时间】:2017-07-01 07:17:42
【问题描述】:

我写了以下代码:

#include <iostream>
#include <string>
#include <type_traits>

template<typename, typename = void>
struct is_incrementable : std::false_type {};

template<typename T>
struct is_incrementable<T, decltype( ++std::declval<T&>() )> : std::true_type {};

int main()
{
    std::cout << is_incrementable<std::string>::value << std::endl;
    std::cout << is_incrementable<int>::value << std::endl;
}

当我运行它时,我得到0 0。但我期待0 1

有什么想法吗?

【问题讨论】:

标签: c++ c++11 sfinae


【解决方案1】:

对于std::string,选择主要模板并考虑专业化。但是decltype(++std::declval&lt;T&amp;&gt;())是病态的,所以不考虑,使用主模板(非特化模板),导致0

如果你使用int,它会变得有点复杂。编译器一如既往地选择主模板,然后考虑特化(这是因为特化总是被认为是更好的匹配)。 int 的特化是 &lt;int, int&amp;&gt;,但它与非特化模板 &lt;int, void&gt; 不匹配(void 是默认模板参数),因此特化被忽略,因为它不匹配。

因此,默认模板参数的类型必须匹配,否则不考虑特化,因为仅当每个模板参数都匹配特化时才考虑特化。

只需在末尾附加一个void() 以使第二个模板参数的特化匹配,因为左边的表达式被丢弃并且void() 的类型是void,它匹配主模板的第二个模板参数。

template<typename T>
struct is_incrementable<T, decltype( ++std::declval<T&>(), void() )> : std::true_type {};

在 C++17 中,您可以使用 std::void_t

【讨论】:

  • 如果我使用template&lt;typename, typename = int &gt; struct is_incrementable : std::false_type {}; 它也不起作用。你也能解释一下吗?谢谢!
  • @Klaus 一个未重载的预增量运算符返回对象本身,因此int i;decltype(++i)int&amp; 而不是int。如果你使用typename = int&amp;,它也会打印0 1
猜你喜欢
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
相关资源
最近更新 更多