C++ 限制模板函数,仅允许某些类型
这里说我有一个简单的模板函数,原则上可以接受所有类型:C++ 限制模板函数,仅允许某些类型,c++,templates,c++11,C++,Templates,C++11,这里说我有一个简单的模板函数,原则上可以接受所有类型: template <class Type> std::ostream& operator<< (std::ostream& stream, const Type subject) { stream << "whatever, derived from subject\n"; return stream; } 模板 std::ostream&operator您可以像这样限制过载: temp
template <class Type>
std::ostream& operator<< (std::ostream& stream, const Type subject) {
stream << "whatever, derived from subject\n";
return stream; }
模板
std::ostream&operator您可以像这样限制过载:
template <class T>
std::ostream& my_private_ostream( std::ostream& stream, const T& data )
{ <your implementation> }
template <class T, class A>
std::ostream& operator<< ( std::ostream& stream, const std::vector<T,A>& data )
{ return my_private_ostream(stream,data); }
或者,对于一个看起来更像您的编辑的解决方案,您可以使用C++11,尽管我个人不喜欢它们,因为它们会使代码难以阅读和维护。因此,我强烈推荐前面的解决方案
// Vector type predicate
template <class T>
struct is_vector: std::false_type {};
template <class T, class A>
struct is_vector< std::vector<T,A> >: std::true_type {};
// Array type predicate
template <class T>
struct is_array: std::false_type {};
template <class T, size_t N>
struct is_array< std::array<T,N> >: std::true_type {};
// The overload with the syntax you want
template <class Indexable>
typename std::enable_if<
is_vector<Indexable>::value || is_array<Indexable>::value,
std::ostream&
>::type
operator<< ( std::ostream& stream, const Indexable& data )
{ <your implementation> }
//向量类型谓词
模板
结构是_向量:std::false_类型{};
模板
结构是_vector:std::true_type{};
//数组类型谓词
模板
结构是_数组:std::false_类型{};
模板
结构是_数组:std::true_类型{};
//使用所需语法的重载
模板
typename std::启用\u如果<
是向量::值|是数组::值,
标准::奥斯特雷姆和
>::类型
操作员使用SFINAE执行您的要求
template<typename...>
struct is_vector: std::false_type{};
template<typename T, typename Alloc>
struct is_vector<std::vector<T, Alloc>>: std::true_type{};
template<typename...>
struct is_array: std::false_type{};
template<typename T, std::size_t Size>
struct is_array<std::array<T, Size>>: std::true_type{};
template<typename T>
struct is_my_ostream_type{
enum {
value = is_vector<T>::value || is_array<T>::value
};
};
template<
typename T,
typename = typename std::enable_if<is_my_ostream_type<T>::value>::type
>
std::ostream &operator <<(std::ostream &lhs, const T &rhs){
lhs << "is my special ostream overload";
return lhs;
}
模板
结构是_向量:std::false_类型{};
模板
结构是_向量:std::true_类型{};
模板
结构是_数组:std::false_类型{};
模板
结构是_数组:std::true_类型{};
模板
struct是我的ostream类型{
枚举{
value=is_向量::value | | is_数组::value
};
};
模板<
类型名T,
typename=typename std::enable_if::type
>
std::ostream&operator为此编写一个真正通用的解决方案是很困难的。根据std::vector
或std::array
检查任意类型T
的问题在于后者不是类,而是类模板。更糟糕的是,std::array
是一个带有非类型模板参数的类模板,因此您甚至不能拥有一个同时包含std::vector
和std::array
的参数包
您可以通过显式地将非类型参数包装到类型中来解决这个问题,但它会变得丑陋、快速
这里是我提出的一个解决方案,它将支持默认情况下没有非类型模板参数的任何类或模板类。通过添加包装器类型将非类型参数映射到类型参数,可以支持具有非类型模板参数的模板类
namespace detail{
//checks if two types are instantiations of the same class template
template<typename T, typename U> struct same_template_as: std::false_type {};
template<template<typename...> class X, typename... Y, typename... Z>
struct same_template_as<X<Y...>, X<Z...>> : std::true_type {};
//this will be used to wrap template classes with non-type args
template <typename T>
struct wrapImpl { using type = T; };
//a wrapper for std::array
template <typename T, typename N> struct ArrayWrapper;
template <typename T, std::size_t N>
struct ArrayWrapper<T, std::integral_constant<std::size_t, N>> {
using type = std::array<T,N>;
};
//maps std::array to the ArrayWrapper
template <typename T, std::size_t N>
struct wrapImpl<std::array<T,N>> {
using type = ArrayWrapper<T,std::integral_constant<std::size_t,N>>;
};
template <typename T>
using wrap = typename wrapImpl<typename std::decay<T>::type>::type;
//checks if a type is the same is one of the types in TList,
//or is an instantiation of the same template as a type in TempTList
//default case for when this is false
template <typename T, typename TList, typename TempTList>
struct one_of {
using type = std::false_type;
};
//still types in the first list to check, but the first one doesn't match
template <typename T, typename First, typename... Ts, typename TempTList>
struct one_of<T, std::tuple<First, Ts...>, TempTList> {
using type = typename one_of<T, std::tuple<Ts...>, TempTList>::type;
};
//type matches one in first list, return true
template <typename T, typename... Ts, typename TempTList>
struct one_of<T, std::tuple<T, Ts...>, TempTList> {
using type = std::true_type;
};
//first list finished, check second list
template <typename T, typename FirstTemp, typename... TempTs>
struct one_of<T, std::tuple<>, std::tuple<FirstTemp, TempTs...>> {
//check if T is an instantiation of the same template as first in the list
using type =
typename std::conditional<same_template_as<wrap<FirstTemp>, T>::value,
std::true_type,
typename one_of<T, std::tuple<>, std::tuple<TempTs...>>::type>::type;
};
}
//top level usage
template <typename T, typename... Ts>
using one_of = typename detail::one_of<detail::wrap<T>,Ts...>::type;
struct Foo{};
struct Bar{};
template <class Type>
auto operator<< (std::ostream& stream, const Type subject)
//is Type one of Foo or Bar, or an instantiation of std::vector or std::array
-> typename std::enable_if<
one_of<Type, std::tuple<Foo,Bar>, std::tuple<std::vector<int>,std::array<int,0>>
>::value, std::ostream&>::type
{
stream << "whatever, derived from subject\n";
return stream;
}
名称空间详细信息{
//检查两种类型是否为同一类模板的实例化
模板结构与:std::false\u类型{}相同;
模板
结构与模板相同:std::true\u type{};
//这将用于包装带有非类型参数的模板类
模板
结构wrapImpl{using type=T;};
//std::array的包装器
模板结构ArrayWrapper;
模板
结构阵列振打器{
使用type=std::array;
};
//将std::array映射到ArrayRapper
模板
结构wrapImpl{
使用类型=阵列振打器;
};
模板
使用wrap=typename wrapImpl::type;
//检查类型是否与TList中的类型相同,
//或者是与列表中的类型相同的模板的实例化
//此选项为false时的默认情况
模板
构造一个{
使用类型=std::false\u类型;
};
//仍在要检查的第一个列表中键入,但第一个列表不匹配
模板
构造一个{
使用type=typename::type中的一个;
};
//类型匹配第一个列表中的一个,返回true
模板
构造一个{
使用type=std::true\u类型;
};
//第一个列表已完成,请检查第二个列表
模板
构造一个{
//检查T是否是与列表中第一个模板相同的模板的实例化
使用类型=
typename std::conditional::type;
};
}
//顶级使用
模板
使用one_of=typename detail::one_of::type;
结构Foo{};
结构条{};
模板
自动操作员typename std::启用\u如果<
一种::value,std::ostream&>::type
{
问题的可能重复是,我想包括类型,如std::array,std::array,std::array,…这是一个不同类型的无限系列…不确定是否有办法做到这一点…仍然我找不到答案,如何防止编译器从我的模板函数实例化,当我使用cout时,如何检查eacH有效类型<代码> type = type A或type B或TypeC < /代码>不同于为每个写一个重载?我想写一个模板来处理几个不同的类型。模板的好处是我不必写出每个不同的实例化。这是C++的工作方式,你可以想要任何你喜欢的东西,但并不意味着langu。年龄必须允许。你想要的是可能的,但你必须为每个类实现一个重载(即一个用于vector
s,一个用于array
s,等等)如果您只想实现一个逻辑,可以创建自己的函数<代码> MyOutOutPuthSuths/Cuff>并从重载调用它。事实上,有一个C++ 14的提议,叫做概念Lite,它只是这样做的;允许指定模板类型的谓词。它被拒绝了,可能在C++的未来版本中。我想YO。你可以用C++11做到这一点,但是处理普通类型和模板类型的必要性会让它变得很难看。+1,为每种类型提供显式特征,然后或将它们组合在一起不是很好扩展,但它肯定比我使用的通用特征之一更漂亮。创建一个怪物感觉如何?:)我认为一个C通过对 >:, 和 ,可以预测局部心理痛苦量的C++阅读量。
template<typename...>
struct is_vector: std::false_type{};
template<typename T, typename Alloc>
struct is_vector<std::vector<T, Alloc>>: std::true_type{};
template<typename...>
struct is_array: std::false_type{};
template<typename T, std::size_t Size>
struct is_array<std::array<T, Size>>: std::true_type{};
template<typename T>
struct is_my_ostream_type{
enum {
value = is_vector<T>::value || is_array<T>::value
};
};
template<
typename T,
typename = typename std::enable_if<is_my_ostream_type<T>::value>::type
>
std::ostream &operator <<(std::ostream &lhs, const T &rhs){
lhs << "is my special ostream overload";
return lhs;
}
namespace detail{
//checks if two types are instantiations of the same class template
template<typename T, typename U> struct same_template_as: std::false_type {};
template<template<typename...> class X, typename... Y, typename... Z>
struct same_template_as<X<Y...>, X<Z...>> : std::true_type {};
//this will be used to wrap template classes with non-type args
template <typename T>
struct wrapImpl { using type = T; };
//a wrapper for std::array
template <typename T, typename N> struct ArrayWrapper;
template <typename T, std::size_t N>
struct ArrayWrapper<T, std::integral_constant<std::size_t, N>> {
using type = std::array<T,N>;
};
//maps std::array to the ArrayWrapper
template <typename T, std::size_t N>
struct wrapImpl<std::array<T,N>> {
using type = ArrayWrapper<T,std::integral_constant<std::size_t,N>>;
};
template <typename T>
using wrap = typename wrapImpl<typename std::decay<T>::type>::type;
//checks if a type is the same is one of the types in TList,
//or is an instantiation of the same template as a type in TempTList
//default case for when this is false
template <typename T, typename TList, typename TempTList>
struct one_of {
using type = std::false_type;
};
//still types in the first list to check, but the first one doesn't match
template <typename T, typename First, typename... Ts, typename TempTList>
struct one_of<T, std::tuple<First, Ts...>, TempTList> {
using type = typename one_of<T, std::tuple<Ts...>, TempTList>::type;
};
//type matches one in first list, return true
template <typename T, typename... Ts, typename TempTList>
struct one_of<T, std::tuple<T, Ts...>, TempTList> {
using type = std::true_type;
};
//first list finished, check second list
template <typename T, typename FirstTemp, typename... TempTs>
struct one_of<T, std::tuple<>, std::tuple<FirstTemp, TempTs...>> {
//check if T is an instantiation of the same template as first in the list
using type =
typename std::conditional<same_template_as<wrap<FirstTemp>, T>::value,
std::true_type,
typename one_of<T, std::tuple<>, std::tuple<TempTs...>>::type>::type;
};
}
//top level usage
template <typename T, typename... Ts>
using one_of = typename detail::one_of<detail::wrap<T>,Ts...>::type;
struct Foo{};
struct Bar{};
template <class Type>
auto operator<< (std::ostream& stream, const Type subject)
//is Type one of Foo or Bar, or an instantiation of std::vector or std::array
-> typename std::enable_if<
one_of<Type, std::tuple<Foo,Bar>, std::tuple<std::vector<int>,std::array<int,0>>
>::value, std::ostream&>::type
{
stream << "whatever, derived from subject\n";
return stream;
}