【问题标题】:Partial template specialization, invalid use of incomplete type部分模板特化,不完整类型的无效使用
【发布时间】:2013-06-24 22:41:12
【问题描述】:

我有三个示例程序,其中两个可以编译,一个不能编译。这三个都是使用 g++ 4.8.1 编译的,使用命令行:g++ --std=c++11 -Wall -pedantic -o foo foo.cc。有问题的代码是一个一次性示例,旨在展示问题,本身并不有用。

潜在的问题是一个模板类,它需要一个专门化来处理std::promise<void>::set_value() 不带参数的事实。这个问题出现在Foo::_call()方法中。

我想工作的版本,叫它版本A,失败了:

#include <future>

template <typename A, typename T>
class Foo
{
  private:
    std::function<T ()> _f;
    std::promise<T> _p;

    static void _call(std::function<T ()> &f, std::promise<T> &p) {
        p.set_value(f());
    }

  public:
    Foo(std::function<T ()> x) : _f(x) {}

    void set_promise() {
        _call(_f, _p);
    }
};

template<typename A>
inline void Foo<A, void>::_call(
    std::function<void ()> &f, std::promise<void> &p)
{
    f();
    p.set_value();
}

int bar()
{
    return 4;
}

void baz()
{
}

int main()
{
    Foo<int, int> a(bar);
    a.set_promise();
    Foo<int, void> b(baz);
    b.set_promise();
}

错误是:

foo.cc:24:53: error: invalid use of incomplete type ‘class Foo<A, void>’
     std::function<void ()> &f, std::promise<void> &p)
                                                     ^
foo.cc:4:7: error: declaration of ‘class Foo<A, void>’
 class Foo
       ^
foo.cc: In instantiation of ‘static void Foo<A, T>::_call(std::function<_Res()>&, std::promise<T>&) [with A = int; T = void]’:
foo.cc:18:21:   required from ‘void Foo<A, T>::set_promise() [with A = int; T = void]’
foo.cc:44:19:   required from here
foo.cc:11:9: error: invalid use of void expression
         p.set_value(f());
         ^


以下测试 B 编译。它取出了额外的模板参数AFoo。实际上,我不希望这样,因为我的非玩具类需要该参数。

#include <future>

template <typename T>
class Foo
{
  private:
    std::function<T ()> _f;
    std::promise<T> _p;

    static void _call(std::function<T ()> &f, std::promise<T> &p) {
        p.set_value(f());
    }

  public:
    Foo(std::function<T ()> x) : _f(x) {}

    void set_promise() {
        _call(_f, _p);
    }
};

template<>
void Foo<void>::_call(
    std::function<void ()> &f, std::promise<void> &p)
{
    f();
    p.set_value();
}

int bar()
{
    return 4;
}

void baz()
{
}

int main()
{
    Foo<int> a(bar);
    a.set_promise();
    Foo<void> b(baz);
    b.set_promise();
}


测试 C 也可以编译。它将_call() 静态方法从Foo 中提取出来,成为一个模板函数。我也不想这样做,因为_call 应该属于Foo。虽然这可行,但它并不优雅。

#include <future>

template<typename T>
inline void _call(std::function<T ()> &f, std::promise<T> &p)
{
    p.set_value(f());
}

template<>
void _call(std::function<void ()> &f, std::promise<void> &p)
{
    f();
    p.set_value();
}

template <typename A, typename T>
class Foo
{
  private:
    std::function<T ()> _f;
    std::promise<T> _p;

  public:
    Foo(std::function<T ()> x) : _f(x) {}

    void set_promise() {
        _call(_f, _p);
    }
};

int bar()
{
    return 4;
}

void baz()
{
}

int main()
{
    Foo<int, int> a(bar);
    a.set_promise();
    Foo<int, void> b(baz);
    b.set_promise();
}


那么,问题是,为什么 A 会失败?有没有办法在不求助于 B 或 C 的情况下解决这个问题?

【问题讨论】:

标签: templates c++11 partial-specialization


【解决方案1】:

部分模板特化仅适用于整个类模板。你不能只专注于一个成员。

一种解决方案是引入一个基类并专门化它。

#include <future>

template< typename T >
struct Foo_base {
    static void _call(std::function<T ()> &f, std::promise<T> &p) {
        p.set_value(f());
    }
};

template<>
struct Foo_base< void > {
    static void _call(std::function<void ()> &f, std::promise<void> &p)
    {
        f();
        p.set_value();
    }
};

template <typename A, typename T>
class Foo : Foo_base< T >
{
private:
    using Foo::Foo_base::_call;
    std::function<T ()> _f;
    std::promise<T> _p;

public:
    Foo(std::function<T ()> x) : _f(x) {}

    void set_promise() {
        _call(_f, _p);
    }
};

【讨论】:

    猜你喜欢
    • 2010-09-14
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-23
    • 2019-12-23
    相关资源
    最近更新 更多