我写了以下代码:
#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
。
有什么想法吗?
答案 0 :(得分:21)
对于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
。