我想知道c ++ 11 / c ++ 14是否/已经支持像vector<auto>
这样的东西?
如果没有,有什么理由吗?
答案 0 :(得分:8)
不直接支持,也不会立即明确您希望它做什么。
评论已经提到了一些用于创建异构集合的可能性(例如Boost any
和variant
类)。我希望这不是你所追求的,因为异构集合与C ++的搭配很差,所以使用它们是丑陋而笨拙的。我认为有些情况/情况确实是最好的选择,但至少根据我的经验,这些情况相当罕见。
你可能想要的另一种可能的解释是一个向量(一般来说就像auto
)只包含一个类型,但是这个类型是从初始化器中推导出来的,所以如果你从一些{{{ 1}} s,你得到int
,如果你从某些字符串初始化它,你就得到vector<int>
,依此类推。尽管该语言并不直接支持,但至少在某种程度上很容易模拟它。模板类无法推断模板参数,但模板功能可以/可以。因此,我们可以创建一个微小的函数模板来获取一些初始值,推导出它们的类型,并返回该类型的向量。例如:
vector<string>
这将返回template <class T>
std::vector<T> make_vector(std::initializer_list<T> init) {
return std::vector<T>(init);
}
(从初始化列表中的数据类型推导出vector<T>
),因此您可以执行以下操作:
T
最后一个需要用户定义的文字运算符,它是C ++ 14中的新功能(许多编译器还不支持)。其余的应该适用于C ++ 11。
在N3602中也有一些讨论(以及{{3}}中的提议)添加一个功能(可能是C ++ 17),您可以在其中定义auto a = make_vector({ 1, 2, 3, 4 }); // a -> vector<int>
auto b = make_vector({ 1.0, 2.0, 3.0 }); // b -> vector<double>
auto c = make_vector({ "1"s, "2"s, "3"s }); // c -> vector<std::string>
之类的内容。上面,但作为类的模板化构造函数。这将允许您在构造函数上使用参数推导来推断整个类的模板参数,因此您可以执行以下操作:
make_vector
警告:这已被提议但未被接受。它可以(轻松地)永远被接受 - 即使它被接受,它也可能在发生之前被显着改变。
答案 1 :(得分:4)
不,不是在C ++ 11或C ++ 14中,已经完成并发布。
但vector<auto>
和类似tuple<auto...>
之类的内容可能会在C ++ 17中作为Concepts工作的一部分。
很自然地,std::vector<T>
可用于函数模板和类模板部分特化,T
是模板参数,而且多态lambda允许{{1}作为函数参数类型(这是带有推导参数的函数模板的简写)。
概念TS允许将“通用函数”声明为:
auto
因为你可以有这样的功能模板:
auto func(auto arg);
将通用函数语法扩展为允许:
是有意义的template<typename T>
auto func(std::vector<T> v);
一旦你在函数声明中允许它,也应该可以在变量声明中允许它:
auto func(std::vector<auto> v);
它不在C ++ 11中的原因是std::vector<auto> v = function_returning_vector_of_something();
是新的,并且过于雄心勃勃,试图让它做得太多。在C ++中,14多态lambdas是新的,再次,进一步扩展auto
的使用将是雄心勃勃的。
对于C ++ 17,我们在实际代码中使用auto
有更多经验,编译器编写者熟悉实现它,并且不需要太多努力就知道什么是可能的。
答案 2 :(得分:1)
boost::any
可以存储任何可以复制的类型的实例,这种类型很多。
为了从any
中获取数据,您必须知道存储在其中的确切类型。
写一个简单的any
并不难:
#include <memory>
#include <utility>
struct any_internal {
virtual any_internal* clone() const = 0;
virtual ~any_internal() {};
};
template<class T>
struct any_details;
class any {
std::unique_ptr<any_internal> internal;
public:
any() = default;
any( any && ) = default;
any( any const&& o):any(o) {}
any( any & o ):any( const_cast<any const&>(o) ) {}
any& operator=( any && ) = default;
any& operator=( any const&& o ) { return this->operator=( o ); };
any& operator=( any & o ) { return this->operator=( const_cast<any const&>(o) ); };
any( any const& o ):internal( o.internal?o.internal->clone():nullptr ) {}
any& operator=( any const& o ) {
any tmp(o);
using std::swap;
swap( internal, tmp.internal );
return *this;
}
template<class U>
void reset( U&& o );
template<class U, class... Args>
void emplace( Args&&... args );
template<class U>
any( U&& o );
template<class U>
any& operator=(U&& o);
template<class T> T* get();
template<class T> T const* get() const;
template<class T> T* fast_get();
template<class T> T const* fast_get() const;
explicit operator bool() const { return internal!=nullptr; }
};
template<class T>
struct any_details : any_internal {
T t;
template<class...Args>
any_details( Args&&... args ):t(std::forward<Args>(args)...) {}
any_internal* clone() const override { return new any_details<T>{t}; }
};
template<class U, class... Args>
void any::emplace( Args&&... args ) {
internal.reset( new any_details<U>( std::forward<Args>(args)... ) );
}
template<class U>
void any::reset( U&& o ) {
emplace<typename std::decay<U>::type>( std::forward<U>(o) );
}
template<class U>
any::any( U&& o ) {
reset( std::forward<U>(o) );
}
template<class U>
any& any::operator=(U&& o) {
reset( std::forward<U>(o) );
return *this;
}
template<class T> T* any::get() {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::get() const {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T* any::fast_get() {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::fast_get() const {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
并且std::vector<any>
的行为与您希望std::vector<auto>
的行为非常相似。
通过小缓冲区优化可以实现更高的效率(例如,如果T
很小,则将any
存储在t
内,而不是使用堆。)
您可能还想从get
分割fast_get
,其中get
执行dynamic_cast
而fast_get
执行static_cast
,再次提高效率。 (如果您确切知道,可以fast_get
)
基本上这是一个谨慎的void*
。