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

Why is the template specialization not chosen?

我写了下面的代码:

#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.

有什么想法吗?

对于std::string,选择主要模板并考虑专业化。但是 decltype(++std::declval<T&>()) 是病式的,所以没有考虑,使用了主模板(非专用模板),结果是 0.

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

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

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

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

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