2015-01-21 78 views
0

我想知道爲什麼此代碼不能編譯,給人的錯誤:不完全類型的std :: tuple_size < aveure>嵌套名指定錯誤:不完全類型...嵌套名指定中使用

我用如果函數與類型不匹配,但甚至無法編譯它,則會出現運行時錯誤。

#include <iostream> 
#include <typeinfo> 
#include <tuple> 

struct aveure{ 
    int que; 
}; 

template<typename T> 
void prova(T valor){ 
    int s; 
    if (typeid(valor) == typeid(aveure)) // Even having if (true) 
              // would cause the same error 
     s=valor.que; 
    else 
     s = std::tuple_size<T>::value; // ERROR !!! Even when T is a 
             // struct aveure, not a tuple 
    std::cout << s; 
} 

int main() { 
    aveure qui; 
    qui.que=2; 
    prova<aveure>(qui); 
    return 0; 
} 

當然,這個錯誤是可以解決的分裂功能:

#include <iostream> 
#include <typeinfo> 
#include <tuple> 

struct aveure{ 
    int que; 
}; 

template< typename T > 
int len(T val){ 

    return(std::tuple_size<T>::value); 
} 

template<> 
int len(aveure quan){ 
    return quan.que; 
} 


template<typename T> 
void prova(T valor){ 
    int s = len(valor); 

    std::cout << s<<std::endl; 
    } 

int main() { 
    aveure qui; 
    qui.que=2; 
    prova<aveure>(qui);        // returns 2 
    auto first = std::make_tuple (10,'a',"hola"); 
    prova<decltype(first)>(first);     // returns 3 

    return 0; 
} 

有沒有更好的解決辦法來解決呢?

回答

0

你不能寫這樣的靜態代碼檢查。使用C++,函數中的每一行都必須是可編譯的。在一個模板函數中,每一行必須對每個被調用的類型都有效。於是:

template <typename T> 
void prova(T valor){ 
    int s; 
    if (typeid(valor) == typeid(aveure)) 
     s = valor.que; // valid ONLY for aveure 
    else 
     s = std::tuple_size<T>::value; // valid ONLY for std::tuple 
    std::cout << s; 
} 

因此,這個函數沒有編譯的希望。你可以做什麼,而不是僅僅是prova了兩種不同的情況提供重載:

void prova(aveure valor) { 
    std::cout << valor.que; 
} 

template <typename... Args> 
void prova(std::tuple<Args...>) { 
    std::cout << sizeof...(Args); 
} 

或者你也可以使用所謂SFINAE。您的if語句必須以編譯器僅編譯一個或另一個分支並僅用於有效類型的方式進行重構。這是你的邏輯直接轉化爲:

template <typename T> 
typename std::enable_if< 
    std::is_same<T, aveure>::value // T is an aveure 
>::type 
prova(T valor) { 
    std::cout << valor.que; 

}

template <typename T> 
typename std::enable_if< 
    !std::is_same<T, aveure>::value // else { ... } 
>::type 
prova(T valor) { 
    std::cout << std::tuple_size<T>::value; 

}

+0

謝謝你的回答,巴里。很有用。我發現了兩篇很好的文章來補充您關於SFINAE的觀點:[link](http://oopscenities.net/2012/04/30/c-sfinae/)和[link](https://debugfailure.wordpress.com/2009/10/06 /理解-SFINAE /)。無論如何,我將繼續使用我提出的解決方案,因爲在區分普通類型時不需要SFINAE,而不需要這些類型的屬性(例如迭代性等)。 – nibrot 2015-01-22 09:48:47

0

擺在首位,類型不完全確定。你將不得不做這樣的事情:

std::tuple<decltype(valor)> mytuple; 
... 
s = std::tuple_size<decltype(mytuple)>::value; 

的主要問題,雖然是: S = valor.que; 傳遞給prova(T)的每個typename T必須支持T :: que。 你不能用if-else引起這個問題。

我想,既然你知道在這一點上的確切類型T的,你可以用投逃脫:

S =((aveure *)&勇敢) - >闕;

但是這不被推薦。

最後,您可以添加一個演員操作符來實現並且不用去引用: struct aveure {int} operator int(){return que;} };

... 

if (typeid(valor).name() == typeid(aveure).name()) 
    s=valor; // no need for s=valor.que