重新分解遗留代码我想合并彼此相关的单独模板类/结构(以避免名称空间污染)。
Nested
(下方)是MyStruct
的帮助类,我想将移动到 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
答案 0 :(得分:5)
您无法在非命名空间范围内专门化模板,例如您的template<typename TYPE> template<>
struct MyStruct<TYPE>::Nested<...> {};
。
您必须将特化项放在结构定义之外:
template<> template<>
struct MyStruct<int>::Nested<...> {};
但是现在你还有另外一个问题,如果你想在模板类中专门化一个模板,那么你必须为每个模板类专门化它。你不能只专注一个成员函数,你必须专注于整个班级。
所以,你需要这样做:
template<typename SELECTOR>
struct Nested; // Default invalid SELECTOR
template<>
struct Nested<YES> { /*...*/ };
template<>
struct Nested<NO> { /*...*/ };
另外,你真的不需要SFINAE:
{{1}}
答案 1 :(得分:1)
似乎有两个原因导致您无法编译代码:
内部模板类的完整专业化无法在类中声明。最好的解决方案是添加一个哑默认模板参数,然后声明内部模板类的部分特化。
使用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;
}
答案 2 :(得分:0)
这是一种让它发挥作用的方法:
#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;
}
};
struct Nested实际上是obsolet - 这只是之前单独建模的剩余部分。
我想要合并的是Print()函数。
然而,std :: is_same&lt;&gt;这里需要强制&lt; SEL_TYPE = TYPE&gt;。 否则有人可能会调用
MyStruct<std::string>::Print<int>();