为什么不选择模板专业化?

ell*_*sis 13 c++ sfinae c++11

我写了以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

当我跑它,我得到0 0.但我期待0 1.

有任何想法吗?

Rak*_*111 21

对于std::string,选择主模板并考虑专业化.但是decltype(++std::declval<T&>())格式不正确,因此不予考虑,并使用主要模板(非专用模板),从而产生0.

如果使用int,它会变得有点复杂.主要模板由编译器一如既往地选择,然后考虑专门化(这是因为专门化总是被认为是更好的匹配).专门化适用<int, int&>int,但它与非专用模板<int, void>(void默认模板参数)不匹配,因此专业化将被忽略,因为它不匹配.

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

只需在末尾附加一个void()以对第二个模板参数进行特化匹配,因为左表达式被丢弃,而类型为void()is void,它与主模板的第二个模板参数匹配.

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

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

  • @Klaus一个非重载的预增量运算符返回对象本身,因此`int i;`的`decltype(++ i)`是`int&`而不是`int`.如果你使用`typename = int&`,它也会打印`0 1`. (2认同)