【问题标题】:Invalid use of incomplete type in conversion operator with forward declaration在具有前向声明的转换运算符中无效使用不完整类型
【发布时间】:2014-05-08 14:03:32
【问题描述】:

我在这样的头文件中定义了一个类(虽然这是一个精简的版本):

my_class.hpp

// header guard

template<typename T, std::size_t First, std::size_t Second, class Enable = void>
class other_class;

template<typename T, std::size_t Size, class Enable = void>
class my_class;                        // I have my reasons

template<typename T, std::size_t Size>
class my_class<T, Size, typename std::enable_if<condition1>::type>{
    public:
        template<
                std::size_t S = Size,
                typename = typename std::enable_if<other_condition1>::type
        >
        operator other_class<T, 1, Size>();
};

template<typename T, std::size_t Size>
class my_class<T, Size, typename std::enable_if<condition2>::type>{
    public:
        template<
                std::size_t S = Size,
                typename = typename std::enable_if<other_condition2>::type
        >
        operator other_class<T, 1, Size>();
};

然后头文件中的另一个类是这样的:

other_class.hpp

#include "my_class.hpp"

template<typename T, std::size_t First, std::size_t Second>
class other_class<T, First, Second, typename std::enable_if<condition>::type>{
    public:
        other_class(...){
            // ...
        }

        my_class<T, First> data[Second];
};

template<typename T, std::size_t Size>
template<std::size_t S, typename>
my_class<T, Size>::operator other_class<T, 1, Size>(){
    return other_class<T, 1, Size>(...);
}

在我想定义转换运算符之前一切都很好:/ 现在我在运算符的实现中收到关于不完整类型 class my_class&lt;T, Size&gt; 的错误。

这对我来说似乎很奇怪,因为我一直使用 my_class 作为 other_class 的数据就好了,这需要它是完整的(它调用类的默认构造函数)。

究竟是什么导致了这里的错误?

系统是 Ubuntu 14.04 和 GCC 4.8.2

【问题讨论】:

  • my_class.hpp 是否包含other_class.hpp
  • 不,否则我不会转发声明
  • 我问是因为当我修复你的代码以替换像condition 和省略号这样的虚拟标识符时,我得到的唯一错误是你使用other_class 没有模板参数@ 987654330@,除非我首先包含my_class.h,否则会出现错误。
  • 你能发布一些我可以实际编译的东西来显示问题吗?
  • @CoffeeandCode 是您在头文件或 .cpp 文件中的实现吗? (将模板实现放在 .cpp 文件中是一个常见错误,会导致您遇到的问题)。

标签: c++ templates c++11


【解决方案1】:

需要在转换运算符的定义中重复std::enable_if&lt;condition&gt;作为my class的第三个参数:

template<typename T, std::size_t Size>
template<std::size_t S, typename>
my_class<T, Size,    typename std::enable_if<condition>::type>::
                  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
operator other_class<T, 1, Size>(){
    // return ...
}

因此,只要 my_class 特化在同一 condition 下,就会实例化此定义。否则,您将进入未定义(因此不完整)的 my_class 的主模板。

使用虚拟条件,compiles in gcc/clang

编辑

检查Understanding (simple?) C++ Partial Template Specialization,我现在意识到,当my_class 特化和转换运算符定义中的模板参数列表不完全匹配时,编译器会将后者解释为成员函数特化本身不是专门化的类。这是不允许的。

我知道一定是这种情况,因为我得到完全相同的编译器错误:

  • gcc:invalid use of incomplete type my_class&lt;T, Size&gt;,和
  • clang:nested name specifier 'my_class&lt;T, Size&gt;::' for declaration does not refer into a class, class template or class template partial specialization.

(当然,这两条消息都没有真正的帮助)。

这里是reduced example 重现错误:

template<typename T>
using enable = typename std::enable_if<sizeof(T)>=0>::type;

template<typename T, typename = void>
struct A;

template<typename T>
struct A<T, enable<T>>{ void f(); };

template<typename T>
void A<T, enable<T>>::  // compiles
// void A<T>::  // does not compile
f() { }

编辑 2

我认为以下内容适用于 iso 14.5.5.3/1:

14.5.5.3 类模板特化的成员

  1. 类模板偏特化成员的模板参数列表应与类模板偏特化的模板参数列表匹配。类模板偏特化成员的模板实参列表应与类模板偏特化的模板实参列表匹配。

【讨论】:

  • 我试过这个,编译器抱怨原型与类中的任何一个都不匹配;尽管我的条件很苛刻,并且使编译器错误看起来非常恶心:L
  • 不知道有多大帮助,但我已将代码缩减为this
  • @CoffeeandCode 检查编辑和链接问题。至于条件,你可以像我简化的例子那样使用别名模板来简化。
  • 如果不是太多,您可以在这里查看实际文件:VectorMatrix
  • @CoffeeandCode 到底在哪里? (也检查编辑 2 并引用标准)。
猜你喜欢
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 2012-06-28
  • 2014-02-02
  • 1970-01-01
  • 2019-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多