Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 限制模板函数,仅允许某些类型_C++_Templates_C++11 - Fatal编程技术网

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; 
}