2015-01-21 77 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