限制模板功能,只允许某些类型
在这里说,我有一个简单的模板功能,原则上可以接受所有种类型:限制模板功能,只允许某些类型
template <class Type>
std::ostream& operator<< (std::ostream& stream, const Type subject) {
stream << "whatever, derived from subject\n";
return stream; }
我只是想用这个模板来清点几类,说std :: vector和boost :: array对象。然而,无论何时我将cout用于其他类型甚至基本类型,例如std :: cout < < int(5);,将是一个编译错误,因为现在有两种可能的运算符< <(std :: ostream,int)的实现,一个是标准C++,另一个是我的模板指定的功能。
我想问一下,是否可以限制我的模板函数,以便它只接受我指定的几种类型?这是如何告诉编译器忽略我的模板当我使用cout < < int(5)。提前致谢。
更清楚,这就是我想做的事:
template <class Type>
std::ostream& operator<< (std::ostream& stream, const Type subject) {
if (Type == TypeA or TypeB or TypeC) //use this template and do these {...};
else //ignore this template, and use operator<< provided in standard c++ library.
}
您可以限制超载是这样的:
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); }
同为std::array
S(你应该标记您的问题C++ 11):
template <class T, size_t N>
std::ostream& operator<< (std::ostream& stream, const std::array<T,N>& data)
{ return my_private_ostream(stream,data); }
或者,对于看起来更像您的编辑的解决方案,您可以使用C++ 11 enable_if
,尽管我对他们有个人厌恶,因为他们倾向于使代码难以阅读和维护。所以我强烈推荐以前的解决方案。
// 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> }
我想编写一个模板来处理几种不同的类型。模板的好处是我不必写出每个不同的实例。 –
这就是C++的工作原理,你可以想要任何你喜欢的东西,但这并不意味着语言必须允许它。你想要什么是可能的,但是你必须为每个_class_实现**一个**重载(即一个用于'vector's,一个用于'array's等等)。如果你只需要一个逻辑实现,你可以创建你自己的函数my_output_stream,并从重载中调用它。事实上,有人提出了一个名为Concept Lite的C++ 14,允许指定模板类型的谓词。它被拒绝了,可能在未来的C++版本中。 – Sheljohn
我想你可以* *做到这一点与C++ 11,但有必要处理正常的类型和模板类型将使它很丑陋。 – TartanLlama
使用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;
}
但是你可能最终只会为每种类型写一个重载,而不是这样做。
为此编写一个真正通用的解决方案很困难。检查任意类型T
与std::vector
或std::array
的问题是后者不是类,它们是类模板。更糟糕的是,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;
}
请不要使用这个,这太可怕了。的[C++模板,仅接受某些类型](
创建一个怪物感觉如何? :)我认为可以通过查看'::',''和'''的密度来预测读取C++的局部心理疼痛的数量。 – Sheljohn
可能重复的http://计算器。COM /问题/ 874298/C的模板,也就是说,接受只,某些类型) –
的问题是,我想包括类型,如性病::阵列,性病::阵列,性病::阵列, ......这就是一个无穷级数不同类型的....不知道是否有一种方法可以做到这一点.. –
我仍然无法找到答案,如何防止实例化编译器从我的模板函数,当我使用cout