为什么不选择模板专业化?
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
。
我写了下面的代码:
#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
。