2

3 つのサンプル プログラムがあり、そのうち 2 つがコンパイルされ、1 つがコンパイルされません。3 つすべては、コマンド ラインを使用して、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 がコンパイルされます。追加のテンプレート パラメータAを に取り出しますFoo。実際には、おもちゃではないクラスがそのパラメーターを必要とするため、これは望ましくありません。

#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に頼らずにこの問題を解決する方法はありますか?

4

1 に答える 1

3

テンプレートの部分的な特殊化は、クラス テンプレート全体にのみ適用されます。1 つのメンバーだけを部分的に特殊化することはできません。

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);
    }
};
于 2013-06-24T23:51:11.380 に答える