Class 模板内的模板专业化 class
Class template specialization within template class
重构遗留代码我想合并彼此相关的单独模板 classes/structs(以避免命名空间污染)。
Nested
(下图)是 MyStruct
的帮手 class,我想将其移动 到 MyStruct
。
但我做不到:
#include <type_traits>
#include <iostream>
struct YES {} ;
struct NO {};
template <typename TYPE>
struct MyStruct
{
template <typename TYPE_AGAIN = TYPE, typename SELECTOR = NO>
struct Nested
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = false>::Print()" << std::endl;
}
};
template <>
struct Nested<TYPE, typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = true>::Print()" << std::endl;
}
};
};
编译器抱怨:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
template <>
^
make: *** [main.o] Error 1
其实我也很困扰必须包括
<typename TYPE_AGAIN = TYPE>
但是没有,抱怨就更多了:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
template <>
^
../MyStruct.h:32:9: error: template parameters not used in partial specialization:
struct Nested<typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
^
../MyStruct.h:32:9: error: ‘TYPE’
make: *** [main.o] Error 1
你不能在非命名空间范围内专门化模板,就像你的例子中的 struct
。
您必须将特化放在结构定义之外:
template<typename TYPE> template<>
struct MyStruct<TYPE>::Nested<...> {};
但是现在你有另一个问题,如果你想在模板中特化一个模板class,你必须为每个模板特化它class。您不能只专门化一个成员函数,您必须专门化整个 class.
所以,你需要这样做:
template<> template<>
struct MyStruct<int>::Nested<...> {};
此外,您真的不需要 SFINAE:
template<typename SELECTOR>
struct Nested; // Default invalid SELECTOR
template<>
struct Nested<YES> { /*...*/ };
template<>
struct Nested<NO> { /*...*/ };
这里有一种方法可以让它发挥作用:
#include <type_traits>
#include <iostream>
template <typename TYPE>
struct MyStruct
{
template <typename SEL_TYPE = TYPE>
static typename std::enable_if<std::is_integral<SEL_TYPE>::value && std::is_same<TYPE, SEL_TYPE>::value, void>::type
Print(void)
{
std::cout << "MyStruct::Nested<is_integral::Print()" << std::endl;
}
template <typename SEL_TYPE = TYPE>
static typename std::enable_if<!std::is_integral<SEL_TYPE>::value && std::is_same<TYPE, SEL_TYPE>::value, void>::type
Print(void)
{
std::cout << "MyStruct::Nested<not is_integral>::Print()" << std::endl;
}
};
嵌套结构实际上已经过时了——这只是之前单独建模的遗留物。
我想合并的是 Print() 函数。
不过,这里需要std::is_same<>来强制。
否则有人可能会调用
MyStruct<std::string>::Print<int>();
您无法编译代码似乎有两个原因:
完全特化 内部模板 class 不能在 class。最好的解决方案是添加一个愚蠢的默认模板参数,然后 声明内部模板的部分特化 class.
模板特化不能直接用std::enable_if
禁用。但是我们可以使用 void_t
技巧来做到这一点。 void_t
是 c++17 的特性,所以对于早期的 c++ 标准,我们需要提供它的定义。我从 http://en.cppreference.com/w/cpp/types/void_t.
中获取了 void_t
定义
因此您可以按如下方式重写代码:
#include <type_traits>
#include <iostream>
#include <type_traits>
//Crédit: cpp-reference.com
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename TYPE>
struct MyStruct
{
//The third parameter is an unused parameter
template <typename TYPE_AGAIN = TYPE, typename SELECTOR = void
, typename = void>
struct Nested
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = false>::Print()" << std::endl;
}
};
//We declare a partial specialization, T go to the third parameter. We use the void_t trick here.
template <class T>
struct Nested<TYPE,
void_t<typename std::enable_if<
std::is_integral<TYPE>::value>::type>
,T>
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = true>::Print()" << std::endl;
}
};
};
int main(){
MyStruct<int>::Nested<>::Print();
return EXIT_SUCCESS;
}
重构遗留代码我想合并彼此相关的单独模板 classes/structs(以避免命名空间污染)。
Nested
(下图)是 MyStruct
的帮手 class,我想将其移动 到 MyStruct
。
但我做不到:
#include <type_traits>
#include <iostream>
struct YES {} ;
struct NO {};
template <typename TYPE>
struct MyStruct
{
template <typename TYPE_AGAIN = TYPE, typename SELECTOR = NO>
struct Nested
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = false>::Print()" << std::endl;
}
};
template <>
struct Nested<TYPE, typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = true>::Print()" << std::endl;
}
};
};
编译器抱怨:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
template <>
^
make: *** [main.o] Error 1
其实我也很困扰必须包括
<typename TYPE_AGAIN = TYPE>
但是没有,抱怨就更多了:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
template <>
^
../MyStruct.h:32:9: error: template parameters not used in partial specialization:
struct Nested<typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
^
../MyStruct.h:32:9: error: ‘TYPE’
make: *** [main.o] Error 1
你不能在非命名空间范围内专门化模板,就像你的例子中的 struct
。
您必须将特化放在结构定义之外:
template<typename TYPE> template<>
struct MyStruct<TYPE>::Nested<...> {};
但是现在你有另一个问题,如果你想在模板中特化一个模板class,你必须为每个模板特化它class。您不能只专门化一个成员函数,您必须专门化整个 class.
所以,你需要这样做:
template<> template<>
struct MyStruct<int>::Nested<...> {};
此外,您真的不需要 SFINAE:
template<typename SELECTOR>
struct Nested; // Default invalid SELECTOR
template<>
struct Nested<YES> { /*...*/ };
template<>
struct Nested<NO> { /*...*/ };
这里有一种方法可以让它发挥作用:
#include <type_traits>
#include <iostream>
template <typename TYPE>
struct MyStruct
{
template <typename SEL_TYPE = TYPE>
static typename std::enable_if<std::is_integral<SEL_TYPE>::value && std::is_same<TYPE, SEL_TYPE>::value, void>::type
Print(void)
{
std::cout << "MyStruct::Nested<is_integral::Print()" << std::endl;
}
template <typename SEL_TYPE = TYPE>
static typename std::enable_if<!std::is_integral<SEL_TYPE>::value && std::is_same<TYPE, SEL_TYPE>::value, void>::type
Print(void)
{
std::cout << "MyStruct::Nested<not is_integral>::Print()" << std::endl;
}
};
嵌套结构实际上已经过时了——这只是之前单独建模的遗留物。
我想合并的是 Print() 函数。
不过,这里需要std::is_same<>来强制
MyStruct<std::string>::Print<int>();
您无法编译代码似乎有两个原因:
完全特化 内部模板 class 不能在 class。最好的解决方案是添加一个愚蠢的默认模板参数,然后 声明内部模板的部分特化 class.
模板特化不能直接用
std::enable_if
禁用。但是我们可以使用void_t
技巧来做到这一点。void_t
是 c++17 的特性,所以对于早期的 c++ 标准,我们需要提供它的定义。我从 http://en.cppreference.com/w/cpp/types/void_t. 中获取了
void_t
定义
因此您可以按如下方式重写代码:
#include <type_traits>
#include <iostream>
#include <type_traits>
//Crédit: cpp-reference.com
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename TYPE>
struct MyStruct
{
//The third parameter is an unused parameter
template <typename TYPE_AGAIN = TYPE, typename SELECTOR = void
, typename = void>
struct Nested
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = false>::Print()" << std::endl;
}
};
//We declare a partial specialization, T go to the third parameter. We use the void_t trick here.
template <class T>
struct Nested<TYPE,
void_t<typename std::enable_if<
std::is_integral<TYPE>::value>::type>
,T>
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = true>::Print()" << std::endl;
}
};
};
int main(){
MyStruct<int>::Nested<>::Print();
return EXIT_SUCCESS;
}