如何优雅地将模板参数限制为 `<Certain_Class<AnyT>>`?
How to elegantly restrict a template argument to be a `<Certain_Class<AnyT>>`?
如何优雅地将Wrapper
的模板参数限制为Wrapper<Any,
MyArray
<AnyT>>
?
- 不要破坏内容支持 (Visual Studio)。
- 可读性高。不要使用 hacky 方法。
由于某些原因,大多数解决方案都喜欢破解。
- 使用 C++ 语法规则使其在第一行显而易见。 (不仅仅是绿色评论)
据我所知,解法有很多,但并不是每一个解法都符合条件。
解决方法 1(模板专业化,失败 1)
template<class T> class MyArray{};
template<class T,class T2> class Wrapper;
template<class T,class T2> class Wrapper<T,MyArray<T2>>{
using Test=int;
};
class B{};
class C{};
int main() {
Wrapper<C,MyArray<B>> wrapper;
return 0;
}
此代码修改自 (@max66)。
IDE 的上下文线索/语法高亮会被混淆。
在我的例子中,它将一些正确的类型标记为错误,例如:-
class ShowError : public Wrapper<B,MyArray<C>>{
Test n=0; //<-- unknown "Test" (intellisense)
};
解决方法 2(有些 hacky field/typedef,失败 2)
template<class T> class MyArray{
public: using MyArrayT=T;
};
template<class T,class T2> class Wrapper{
public: using myT=typename T2::MyArrayT;
//^ assert at compile time
};
这个想法来自 (@Jarod42)
中的评论
class 声明没有提及 MyArray
,它只是使用一种 hacky(可读性较差)的方式 (MyArrayT
) 来强制 T2
是 MyArray
.
解决方法 3(基础 class,失败 2)
class MyArrayBase{};
template<class T> class MyArray : public MyArrayBase{ };
template<class T,class T2> class Wrapper{
//check something around MyArrayBase *object = new T2();
// or "is_base_of"
};
代码修改自Restrict C++ Template Parameter to Subclass and C++ templates that accept only certain types。
它与解决方法 2 有相同的缺点。
对于普通用户来说并不明显。
解决方法 4(SNIFAE,失败 1)
通过在模板 class 声明 (Wrapper
) 上添加 std::enable_if
,我可以获得一个有效的 hack。
不幸的是,内容支持讨厌它。
参考
这是我阅读的其他链接:-
- http://www.informit.com/articles/article.aspx?p=376878(模板模板参数)
- restrict a template function, to only allow certain types(与模板类型无关作为参数)
你可以写一个自定义类型特征is_specialization
,如下:
template<class Type, template<class...> class Template>
struct is_specialization
: std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
: std::true_type {};
那么您只需要 static_assert
对于给定的模板参数 is_specialization
为真:
template<class T,class T2>
class Wrapper {
static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};
如何优雅地将Wrapper
的模板参数限制为Wrapper<Any,
MyArray
<AnyT>>
?
- 不要破坏内容支持 (Visual Studio)。
- 可读性高。不要使用 hacky 方法。
由于某些原因,大多数解决方案都喜欢破解。 - 使用 C++ 语法规则使其在第一行显而易见。 (不仅仅是绿色评论)
据我所知,解法有很多,但并不是每一个解法都符合条件。
解决方法 1(模板专业化,失败 1)
template<class T> class MyArray{};
template<class T,class T2> class Wrapper;
template<class T,class T2> class Wrapper<T,MyArray<T2>>{
using Test=int;
};
class B{};
class C{};
int main() {
Wrapper<C,MyArray<B>> wrapper;
return 0;
}
此代码修改自
IDE 的上下文线索/语法高亮会被混淆。
在我的例子中,它将一些正确的类型标记为错误,例如:-
class ShowError : public Wrapper<B,MyArray<C>>{
Test n=0; //<-- unknown "Test" (intellisense)
};
解决方法 2(有些 hacky field/typedef,失败 2)
template<class T> class MyArray{
public: using MyArrayT=T;
};
template<class T,class T2> class Wrapper{
public: using myT=typename T2::MyArrayT;
//^ assert at compile time
};
这个想法来自
class 声明没有提及 MyArray
,它只是使用一种 hacky(可读性较差)的方式 (MyArrayT
) 来强制 T2
是 MyArray
.
解决方法 3(基础 class,失败 2)
class MyArrayBase{};
template<class T> class MyArray : public MyArrayBase{ };
template<class T,class T2> class Wrapper{
//check something around MyArrayBase *object = new T2();
// or "is_base_of"
};
代码修改自Restrict C++ Template Parameter to Subclass and C++ templates that accept only certain types。
它与解决方法 2 有相同的缺点。
对于普通用户来说并不明显。
解决方法 4(SNIFAE,失败 1)
通过在模板 class 声明 (Wrapper
) 上添加 std::enable_if
,我可以获得一个有效的 hack。
不幸的是,内容支持讨厌它。
参考
这是我阅读的其他链接:-
- http://www.informit.com/articles/article.aspx?p=376878(模板模板参数)
- restrict a template function, to only allow certain types(与模板类型无关作为参数)
你可以写一个自定义类型特征is_specialization
,如下:
template<class Type, template<class...> class Template>
struct is_specialization
: std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
: std::true_type {};
那么您只需要 static_assert
对于给定的模板参数 is_specialization
为真:
template<class T,class T2>
class Wrapper {
static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};