2014-09-30 37 views
5

我想知道如果c + + 11/c + + 14會/已經支持像vector<auto>? 如果沒有,是否有任何理由?是否/會C++ 11/14支持類似於矢量<auto>

+2

它將如何使用? – Cameron 2014-09-30 13:47:36

+1

也許在C++ 999中,你可以'push_back'任何東西到'vector'中。 :P – herohuyongtao 2014-09-30 13:48:55

+0

@cameron,用它​​我們可以寫更多通用的代碼 – 2014-09-30 13:56:45

回答

8

它不直接支持,並且不能立即清楚你想要它做什麼。

評論已經提到了創建異構集合的幾種可能性(如Boost anyvariant類)。我希望這不是你以後的樣子,因爲異構集合與C++很差,因此使用它們很難看,也很笨拙。我想有些情況下這些確實是最好的選擇,但至少在我的經驗中,這些情況相當罕見。你可能想要的另一種可能的解釋是一個向量(就像一般的auto)只有一種類型,但是這種類型是從初始值設定項中推導出來的,所以如果你初始化了一些int的向量, d得到一個vector<int>,如果你從一些字符串初始化它,你會得到一個vector<string>,依此類推。雖然語言不直接支持,但至少在某種程度上很容易模擬它。模板不能/不會推導模板參數,但模板函數 do/can。因此,我們可以創建一個小函數模板來獲取一些初始化器,推導出它們的類型,並返回該類型的向量。例如:

template <class T> 
std::vector<T> make_vector(std::initializer_list<T> init) { 
    return std::vector<T>(init); 
} 

這將返回vector<T>(與T從數據在初始化列表中的類型推斷)一個,所以你可以做這樣的事情:

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> 

這最後一個要求用戶在C++ 14中是新定義的文字操作符(許多編譯器現在還不支持)。其餘的應該與C++ 11一樣好。

也有一些討論(和N3602中的一個建議)添加一個功能(可能是C++ 17),您可以在其中定義類似上面的make_vector,但是像模板化構造函數爲班級。這將讓你使用參數推導的構造推斷該類作爲一個整體的模板參數,所以你可以這樣做:

X x(1);  // deduces as X<int> 
X x(2.0) // deduces as X<double> 

警告,雖然:這已經被提出,但未被接受。它可能(容易)從不被接受 - 即使它是,它可能會發生重大變化之前發生。

+0

我相信你想要的提議是[N3602] (http://www.open-std.org/JTC1/sc22/wg21/docs/papers/2013/n3602.html),目前我認爲這不會發生。 – 2014-09-30 17:09:12

+0

@dyp:經過一番思考(還有一點點閱讀)後,我認爲你是對的 - 至少在這種情況下(也許總的來說,儘管我不確定)通過價值無疑是最有意義的(而我已經相應編輯)。 – 2014-09-30 18:28:35

+0

@JonathanWakely:感謝您的鏈接 - 是的,那是我正在考慮的那個(我已經編輯了答案的鏈接,以及更強硬的措辭警告,它可能永遠不會發生)。 – 2014-09-30 18:33:55

4

不,不在C++ 11或C++ 14中,它們已經完成併發布。

但是有可能vector<auto>和類似的東西tuple<auto...>將作爲Concepts工作的一部分在C++ 17中。

它遵循很自然地從以下事實std::vector<T>可以在功能模板和類模板偏特被用於其中T是模板參數,並且還從一個事實,即多晶型的lambda允許auto作爲函數參數類型(這是速記對於具有推導參數的函數模板)。

的概念TS允許被宣佈爲「通用功能」,如:

auto func(auto arg); 

既然你可以有一個函數模板是這樣的:

template<typename T> 
    auto func(std::vector<T> v); 

是有意義的延長通用函數語法允許:

auto func(std::vector<auto> v); 

一旦你允許它在函數聲明中,它也應該是可以允許它在變量聲明:

std::vector<auto> v = function_returning_vector_of_something(); 

的原因,它是不是在C++ 11是auto是新的,而且它會一直過於雄心勃勃,試圖讓它做太多。在C++中,14個多態lambda表達式是新的,並且再次擴大auto的用法本來就是雄心勃勃的。

對於C++ 17,我們在實際代碼中使用auto有更多的經驗,編譯器編寫者熟悉實現它,並且知道什麼可能沒有太多的努力。

+0

你是說在C++ 17中,編譯器能夠從initializer_list中爲'std :: vector '推導'T'嗎?目前'func({1,2,3,4})'不起作用。 – Jamboree 2014-10-01 02:00:46

+0

我不是說它能夠做任何事情,現在知道它還爲時過早。這個例子的重點不在於初始化列表,而是使用'auto',所以我改變了這個例子。 – 2014-10-01 10:19:07

1

A 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很小,而不是使用堆,則將T存儲在any之內)。

你可能也想從fast_get,其中get做了dynamic_castfast_get做了static_cast,再次拆分效率get。 (當你知道確定的時候,你可以fast_get

基本上這是一個gussied up void*

+0

爲什麼'任何const &&'和'任何&'拷貝ctors? – dyp 2014-09-30 22:29:11

+0

'swap(internal,tmp.internal);'或'internal = std :: move(tmp.internal);' – dyp 2014-09-30 22:43:53

+1

@dyp我有一個通用拷貝ctor&賦值,我明確表示不會在rhs時調用它是一個'任何'。是的,一個'移動'也可以工作:我在做copy-swap,然後懶得執行'void swap(any&,any&)',因爲我注意到它是2行。感謝修復 - 已經寫好了。 – Yakk 2014-09-30 23:02:23