4

テンプレートクラスがありますReader

template<typename T>
class Reader{
    typedef T type;
};

特別な実装(派生クラス)には、署名付きのメソッドがあります

T read(IStream&, any number of arguments, zero possible)

すなわち、クラス IntegerReaderパブリック関数:

template <typename T>
class IntegerReader : public Reader<T>{
public:
    T read(IStream& stream);
    T read(IStream& stream, T min, T max);
    T read(IStream& stream, T min, T max, std::string name);
}

次に、別のリーダーを作成できるラッパーを作成し、引数を使用してリーダーを呼び出します。

私はこれを試しました:

template <typename T, typename... Args>
class ParametrizedReader : public Reader<typename T::type> {
    T reader;
    Args... args;
    ParametrizedReader(T reader, Args... args):reader(reader), args(args){
    }

    typename T::type read(IStream& stream){
        return reader.read(args..., stream);
    }
};
testlib/readerWrapper.hpp:7:6: error: expected unqualified-id before ‘...’ token
testlib/readerWrapper.hpp: In constructor ‘ParametrizedReader<T, Args>::ParametrizedReader(T, Args ...)’:
testlib/readerWrapper.hpp:8:61: error: class ‘ParametrizedReader<T, Args>’ does not have any field named ‘args’
testlib/readerWrapper.hpp: In member function ‘typename T::type ParametrizedReader<T, Args>::read(IStream&)’:
testlib/readerWrapper.hpp:12:22: error: ‘args’ was not declared in this scope

これ:

template <typename T, typename... Args>
class ParametrizedReader : public Reader<typename T::type> {
    std::function<T()> lambda;
    ParametrizedReader(T reader, Args... args){
        lambda = [=](IStream& stream){
            reader.read(stream, args...);
        };
    }

    typename T::type read(IStream& stream){
        return lambda(stream);
    }
};

testlib/readerWrapper.hpp:9:24: error: parameter packs not expanded with ‘...’:
testlib/readerWrapper.hpp:9:24: note:         ‘args’
testlib/readerWrapper.hpp:9:28: error: expansion pattern ‘args’ contains no argument packs

この:

template <typename T, typename... Args>
class ParametrizedReader : public Reader<typename T::type> {
    std::function<T()> lambda;
    ParametrizedReader(T reader, Args... args){
        lambda = [reader, args...](IStream& stream){
            reader.read(stream, args...);
        };
    }

    typename T::type read(IStream& stream){
        return lambda(stream);
    }
};

testlib/readerWrapper.hpp:8:25: error: expected ‘,’ before ‘...’ token
testlib/readerWrapper.hpp:8:25: error: expected identifier before ‘...’ token
testlib/readerWrapper.hpp:8:28: error: parameter packs not expanded with ‘...’:
testlib/readerWrapper.hpp:8:28: note:         ‘args’

g++-4.7によるコンパイルエラー

最初の例が正しく、コンパイルする必要があるかどうかはわかりませんが、2番目と3番目の例は正しいと思います。

このバグを見つけましたが、修正されていないようです。

回避策はありますか?どうすればやりたいことができますか?

4

3 に答える 3

4

この問題を回避するには、引数をラムダにバインドし、キャプチャしないようにします。

ParametrizedReader(T reader, Args... args){
    lambda = std::bind(
        [=](IStream& stream, Args... as){
            reader.read(stream, as...);
        }, args...);
}

@Alexandreが言うように、正確な引数タイプでクラステンプレートをパラメーター化しないことをお勧めしますが、次のようになります。

template <typename T>
class ParametrizedReader : public Reader<typename T::type> {
    std::function<T()> lambda;
    template<typename... Args>
    ParametrizedReader(T reader, Args... args){
        lambda = std::bind(
            [=](IStream& stream, Args... as){
                reader.read(stream, as...);
            }, args...);
    }
    // ...
};

(注:テストされていません。)

また、2番目のスニペットをドロップstd::bindして、2番目または3番目のソリューションのように試してみてください。今回は、可変個引数関数テンプレートを使用します。多分それはうまくいく、誰が知っている。

于 2012-10-05T21:55:57.460 に答える
3

これは既知のバグを思い出させます:http://gcc.gnu.org/bugzilla/show_bug.cgi ?id=41933少なくともgcc4.6.2および4.7.xシリーズに影響します。

Clang 3.1は、ラムダキャプチャの可変個引数の処理に問題はありません。

おそらく、昔ながらのルートに移動して、それらをタプルに格納することができます:http: //liveworkspace.org/code/7d4347021aaf004489591e78654f0233

#include <tuple>
#include <vector>
#include <string>

////////////////////////////////////
template<int ...>         struct seq                         {                         }; 
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {                         }; 
template<int ...S>        struct gens<0, S...>               { typedef seq<S...> type; }; 

////////////////////////////////////

template<typename T>
struct Reader
{
    typedef T type;
};

//Special implementations (derrived classes) have methods with signature
struct IStream {};

template <typename T>
class IntegerReader : public Reader<T>
{
public:
    T read(IStream& stream);
    T read(IStream& stream, T min, T max);
    T read(IStream& stream, T min, T max, std::string name);
};

template <typename T, typename... Args>
class ParametrizedReader : public Reader<typename T::type>
{
    T _reader;
    std::tuple<Args...> _args;
public:
    ParametrizedReader(T reader, Args... args)
        : _reader(reader), _args(std::forward<Args>(args)...)
    {
    }

    typename T::type read(IStream& stream)
    {
        callFunc(typename gens<sizeof...(Args)>::type());
    }

    template<int ...S>
        void callFunc(seq<S...>)
        {
            func(std::get<S>(_args) ...);
        }
};

template <typename T, typename... Args>
ParametrizedReader<T, Args...> make_parameterized_reader(T reader, Args... args)
{
    return ParametrizedReader<T, Args...>(reader, std::forward<Args>(args)...);
}

int main(int argc, const char *argv[])
{
    Reader<char> reader;
    auto pr = make_parameterized_reader(reader, "stuff", 3.14, std::string("you can think of"), std::vector<int> { 1,2,3 });
}
于 2012-10-05T20:40:28.430 に答える
0

クラステンプレートからパラメータパックを削除し、完全な転送とstd::bindを使用します。

template <typename T>
class ParametrizedReader : public Reader<typename T::type> 
{
    std::function<T()> lambda;

    template <typename... Args>
    ParametrizedReader(T reader, Args&&... args)
    {
        using namespace std::placeholders;

        lambda = std::bind(
            std::mem_fn(&Reader::read),
            _1,
            std::forward<Args>(args)...);
    }

    typename T::type read(IStream& stream)
    {
        return lambda(stream);
    }
};
于 2012-10-05T20:43:00.503 に答える