【问题标题】:Error: Variadic template class has incomplete type错误:可变参数模板类的类型不完整
【发布时间】:2020-07-31 00:09:04
【问题描述】:

我有代码:

#include <unordered_set>

template<typename First, typename Enable = void, typename ... T>
class converged_is_exactly_equal_functor;

template<typename ... T>
bool converged_is_exactly_equal(const T& ...);

template <typename T, typename std::enable_if<std::is_arithmetic<T>::value || std::is_enum<T>::value>::type* = nullptr>
bool is_exactly_equal(const T other, const T one) {
    return (other == one);
}

template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) == 1>, T ...>
{
    private:
        static std::unordered_set<First*> visited_values;
        void visit_value (const First& value_to_visit) {
            visited_values.insert(&value_to_visit);
        }
        bool is_visited (const First& value_to_check) {
            return (visited_values.find(&value_to_check) != visited_values.end());
        }
    public:
        converged_is_exactly_equal_functor(void){}
        bool operator () (const First& first_arg, const T& ... expanded_args) const {
            if (!is_visited(first_arg)) {
                visit_value(first_arg);
                return is_exactly_equal(first_arg, expanded_args ...);
            }
            return true;
        }
};

template<typename First, typename ... T>
std::unordered_set<First*> converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) == 1>, T ...>::visited_values;

template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) != 1>, T ...>
{
    public:
        converged_is_exactly_equal_functor(void){}
        bool operator () (const First& first_arg, const T& ... expanded_args) const {
            return is_exactly_equal(first_arg, expanded_args ...);
        }
};

template<typename ... T>
bool converged_is_exactly_equal(const T& ... expanded_args) {
    converged_is_exactly_equal_functor<T ... > my_functor;
    return my_functor(expanded_args ...);
}

class a {
    public:
    a() : dbid(1), lsb(123) {}
    int dbid;
    long lsb;
};


bool operator == (const a& other, const a& one) {
    if (&other == &one)
        return true;
    return (
        converged_is_exactly_equal(other.dbid, one.dbid) &&
        converged_is_exactly_equal(other.lsb, one.lsb)
    );
}

int main(void) {
a as, bs;

as == bs;
}

鉴于 class a 是一组简单的原始类型,为什么我会收到以下错误:

my_file.cxx: In instantiation of 'bool converged_is_exactly_equal(const T& ...) [with T = {long int, long int}]':
my_file.cxx:690:56:   required from here
my_file.cxx:682:48: error: 'converged_is_exactly_equal_functor<long int, long int> my_functor' has incomplete type
     converged_is_exactly_equal_functor<T ... > my_functor;

我认为该错误与专有数据结构无关,但我不明白为什么该类型可能不完整。我在同一个文件中包含 unordered_set 的头文件。

is_exactly_equal(T) 的所有定义都在前向声明和模板定义之间完成。

请尽可能明确,因为我倾向于发现一般来说理解模板错误很复杂。

我可以提供更多必要的信息,但我明天才会回来。 (这个让我筋疲力尽:-/)

【问题讨论】:

  • 请同时提供实例化模板的代码。我假设operator== 应该是模板化的?
  • 我不明白。我相信实例化模板的代码就在那里。 "operator==" 是一一定义的,因为它涵盖了每个不同结构的成员比较。
  • 没有实例化,它似乎编译fine。 (我制作了operator== 一个模板)。它不是提供的代码中的类模板的成员。当然,有可能误解了这个问题。
  • 我们需要的是minimal reproducible example,我们可以自己编译以重现错误。为了查看我们是否遇到相同的错误,我们每个人都需要添加适当的包含并选择一种方法来处理 operator== 中使用的缺失类。
  • 我添加了 main 和实例化,产生了同样的错误。将更新问题。

标签: c++ templates variadic-templates sfinae


【解决方案1】:

问题出在converged_is_exactly_equal_functor 类及其使用中。

你声明如下

template<typename First, typename Enable = void, typename ... T>
class converged_is_exactly_equal_functor;

没有定义它。

然后你定义了两个特化:一个用于sizeof...(T) == 1的案例

template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) == 1>, T ...>
{
  // ...
};

还有一个用于案例sizeof...(T) != 1

template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) != 1>, T ...>
 {
   // ...
 };

你使用converged_is_exactly_equal里面的类

template<typename ... T>
bool converged_is_exactly_equal(const T& ... expanded_args) {
    converged_is_exactly_equal_functor<T ... > my_functor;
    return my_functor(expanded_args ...);
}

在你的程序中被调用两次

    converged_is_exactly_equal(other.dbid, one.dbid) &&
    converged_is_exactly_equal(other.lsb, one.lsb)

第一次有两个int,第二次有两个long

在这两种情况下,您都使用不是void 的第二个模板参数声明了converged_is_exactly_equal_functor 值,因此不匹配特化,因此匹配主模板,但主模板已声明但未定义。

所以错误。

一种可能的解决方案:丢弃 SFINAE 部分并简单地为以下类型的可变参数列表声明/定义类(旧的 sizeof...(T) != 0

template <typename F, typename ... Ts>
class converged_is_exactly_equal_functor
 {
   public:
      converged_is_exactly_equal_functor ()
       { }

      bool operator () (F const & fa, Ts const & ... ea) const
       { return is_exactly_equal(fa, ea ...); }
 };

并只为两种情况定义一个特化(旧的sizeof...(T) == 1 情况)

template <typename First, typename Second>
class converged_is_exactly_equal_functor<First, Second>
 {
   private:
      static std::unordered_set<First const *> visited_values;

      void visit_value (First const & value_to_visit) const
       { visited_values.insert(&value_to_visit); }

      bool is_visited (First const & value_to_check) const
       { return (visited_values.find(&value_to_check) != visited_values.end()); }

   public:
      converged_is_exactly_equal_functor ()
       { }

      bool operator () (First const & fa, Second const & sa) const
       {
            if ( false == is_visited(fa) )
             {
               visit_value(fa);

               return is_exactly_equal(fa, sa);
             }

            return true;
        }
 };

template <typename First, typename Second>
std::unordered_set<First const *> converged_is_exactly_equal_functor<First, Second>::visited_values;

注意我添加了一些const 让它编译。

【讨论】:

  • 非常感谢!建议的解决方案解决了我的问题并保持了代码意图。我不知道我可以仅根据参数的数量对其进行专门化,认为这会是一个歧义哈哈。
  • @thiago - 没有歧义,因为专业化比主要版本“更专业化”。粗略地说:当所有匹配 A 的参数集也匹配 B 但至少有一组参数匹配 B 但不匹配 A 时,模板 A 比模板 B“更专业”。在我们的例子中,a 有两种类型set ever 匹配两个模板,但三个类型匹配主模板但不匹配专业化。
猜你喜欢
  • 2011-12-14
  • 1970-01-01
  • 2018-03-11
  • 2014-11-22
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多