错误:不完整的类型..在嵌套名称说明符中使用

error: incomplete type ... used in nested name specifier

本文关键字:说明符 嵌套 类型 错误      更新时间:2023-10-16

我想知道为什么这段代码无法编译,给出错误:不完整的类型 std::tuple_size 用于嵌套名称说明符

我希望在函数与类型不匹配但甚至无法编译它的情况下出现运行时错误。

#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;
}

有没有更好的解决方案来解决它?

你不能像这样编写静态代码检查。使用 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;

}

首先,没有完全指定类型。您必须执行以下操作:

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

但主要问题是: s=valor.que;传递给 prova(T) 的每个类型名 T 都必须支持 T::que。你不能用if-else来解决这个问题。

我想既然你此时知道T的确切类型,你可以侥幸逃脱一个演员表:

s=((aveure *) &valor)->que;

但不建议这样做。

最后,您可以在 aveure 中添加一个强制转换运算符,而无需为取消引用而烦恼: struct aveure{ int que; 运算符 int() {return que;} };

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