2016-08-12 45 views
3
using Name = std::string; 
using NodeType = int; 
using ElementType = int; 

std::tuple<Name, NodeType, ElementType> myTuple("hi", 12, 42); 

cout<<std::get<NodeType>(myTuple)<<endl; 

這會產生編譯錯誤。是否有可能通過重複的std :: tuple類型名稱獲取?

我可以使用std::get<1>(myTuple),但它不容易閱讀爲std::get<NodeType>(myTuple),有沒有什麼辦法在這種情況下按類型獲取價值?

+5

好像你可能只是一個命名的類最好避免頭痛。 – TartanLlama

+0

@TartanLlama是的。唯一的問題是這個元組在其他文件中定義,我無法更改... – Deqing

+0

爲什麼你想要那個? – edmz

回答

4
enum {NodeTypeIdX=1, ElementTypeIdx=2}; 

std::get<NodeTypeIdx>(myTuple); 

這個作品是自我記錄。

std::get<Type>語法不支持std::get<Type, which_one>或類似的東西。它只適用於類型是唯一的。由於您無法控制元組的定義,因此您可以執行任何操作(定義)以使std::get<Type>選項無效。

另一方面,誰在乎你使用的關鍵字是一個類型還是一個枚舉常量?重要的部分是它有一個自我記錄的名字。

+0

我使用了一個const int,但我相信enum是一樣的。 – Deqing

7

NodeTypeElementType是相同的類型,即inttypedefusing不要創建一個新的類型,只有名字。

因此,不能按照類型獲取最後一個條目,因爲它們的類型在元組中不唯一。

+0

我們已經提出了多年來強烈/不透明typedefs的建議,並且他們中沒有一個將其納入標準。這個答案是我們確實需要它們標準化的另一個證明 – KABoissonneault

+1

下面是強類型定義的「解決方法」:enum class NodeType:int {};和enum class ElementType:int {};'。 – Xeo

0

假設NameNodeTypeElementType不同類型(標籤或許可以幫助):

template <class T> 
struct Names; 

template <> struct Names<Name> { static constexpr int i = 0; }; 
template <> struct Names<NodeType> { static constexpr int i = 1; }; 
template <> struct Names<ElementType> { static constexpr int i = 2; }; 

你可以做空有點用輔助功能:

template <class T> 
constexpr auto index() -> int 
{ 
    return Names<T>::index; 
} 

所以,你得到:

cout<< std::get< index<NodeType>() >(myTuple) << endl; 

我會給你它不是最好的。

+0

如果類型是唯一的,那麼可以直接執行OP直接從C++ 14開始的操作。 –

1

無論您如何命名它,類型都是相同的 - int,ElementTypeNodeType是等同的,無法區分它們。

我會寫存取功能,並使用這些:

using Something = std::tuple<Name, NodeType, ElementType>; 

NodeType& nodeType(Something& tp) 
{ 
    return std::get<1>(tp); 
} 

NodeType nodeType(const Something& tp) 
{ 
    return std::get<1>(tp); 
} 

ElementType& elementType(Something& tp) 
{ 
    return std::get<2>(tp); 
} 

ElementType elementType(const Something& tp) 
{ 
    return std::get<2>(tp); 
} 
// ... 

cout << nodeType(myTuple) << endl; 
elementType(myTuple) = some_type; 
+0

爲了模仿'std :: get',你應該返回引用(並且可能需要'tp'作爲非const引用,或者提供超載)。或者可能使用帶有轉發參考的模板版本以避免代碼重複;) – Holt

+0

@Holt是的,我應該。 (但是我太不熟悉轉發引用來嘗試那個引用。) – molbdnilo

+0

使用轉發引用(例如, 'template auto nodeType_(Tuple && t){return std :: get <1>(std :: forward (t)); }',這會爲你節省大量的寫作(在任何情況下,你應該在'const'版本中返回'const'引用而不是值);) – Holt

0

在其他的答案mentionned,如果tuple包含一個以上的單intstd::get<int>(tuple)將無法​​正常工作,所以它不會爲你工作。

但是,你可以讓你自己的get<>()這是你想要的。以下代碼定義了一個模板函數my_get<Et,P>(tuple),該函數將返回對tupleEt類型的(P+1)th元素的引用。

template<typename Et, size_t P, typename Ct, size_t N, typename Et2> 
typename std::enable_if<std::is_same<Et,Et2>::value && (P == 0), Et&>::type 
    my_get(Ct& c, Et2& e) { return std::get<N>(c); } 

template<typename Et, size_t P, typename Ct, size_t N, typename Et2> 
typename std::enable_if<std::is_same<Et,Et2>::value && (P > 0), Et&>::type 
    my_get(Ct& c, Et2& e) { return my_get<Et,P-1,Ct,N+1>(c); } 

template<typename Et, size_t P, typename Ct, size_t N, typename Et2> 
typename std::enable_if<!std::is_same<Et,Et2>::value, Et&>::type 
    my_get(Ct& c, Et2& e) { return my_get<Et, P, Ct, N+1>(c, std::get<N+1>(c)); } 

template<typename Et, size_t P, typename Ct, size_t N> 
Et& my_get(Ct& c) { return my_get<Et, P, Ct, N>(c, std::get<N>(c)); } 

template<typename Et, size_t P, typename Ct> 
Et& my_get(Ct& c) { return my_get<Et, P, Ct, 0>(c); } 

用法:

void tptest() 
{ 
    std::tuple<double,int,double,int> mytuple(1.0,2, 3.0, 4); 
    std::cout << "my_get<double,0>(mytuple) = " << my_get<double,0>(mytuple) << std::endl; 
    std::cout << "my_get<int,0>(mytuple) = " << my_get<int,0>(mytuple) << std::endl; 
    std::cout << "my_get<double,1>(mytuple) = " << my_get<double,1>(mytuple) << std::endl; 
    std::cout << "my_get<int,1>(mytuple) = " << my_get<int,1>(mytuple) << std::endl; 
} 

輸出:

my_get<double,0>(mytuple) = 1 
my_get<int,0>(mytuple) = 2 
my_get<double,1>(mytuple) = 3 
my_get<int,1>(mytuple) = 4 
相關問題