C++ 创建类的变量包装器

C++ 创建类的变量包装器,c++,templates,lambda,c++11,g++,C++,Templates,Lambda,C++11,G++,我有模板类Reader template<typename T> class Reader{ typedef T type; }; 现在我想创建一个包装器,它将允许我创建另一个读取器,它将调用带有参数的读取器 我试过这个: template <typename T, typename... Args> class ParametrizedReader : public Reader<typename T::type> { T reader;

我有模板类
Reader

template<typename T>
class Reader{
    typedef T type;
};
现在我想创建一个包装器,它将允许我创建另一个读取器,它将调用带有参数的读取器

我试过这个:

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
模板
类参数恐惧者:公共读取器{
T阅读器;
Args…Args;
参数恐惧者(T读取器,Args…Args):读取器(读取器),Args(Args){
}
typename T::类型读取(IStream和stream){
返回reader.read(参数…,流);
}
};
testlib/readerWrapper.hpp:7:6:错误:在“…”标记之前应为非限定id
testlib/readerWrapper.hpp:在构造函数“ParametrizedReader::ParametrizedReader(T,Args…)”中:
testlib/readerWrapper.hpp:8:61:错误:类“ParameterizeDrawer”没有任何名为“args”的字段
testlib/readerWrapper.hpp:在成员函数“typename T::type ParameterizeDreader::read(IStream&)”中:
testlib/readerWrapper.hpp:12:22:错误:“args”未在此作用域中声明
这:

模板
类参数恐惧者:公共读取器{
std::函数lambda;
参数化恐惧者(T读取器,Args…Args){
lambda=[=](IStream和stream){
reader.read(流、参数…);
};
}
typename T::类型读取(IStream和stream){
返回lambda(流);
}
};
testlib/readerWrapper.hpp:9:24:错误:参数包未扩展为“…”:
testlib/readerWrapper.hpp:9:24:note:'args'
testlib/readerWrapper.hpp:9:28:错误:扩展模式“args”不包含参数包
这是:

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’
模板
类参数恐惧者:公共读取器{
std::函数lambda;
参数化恐惧者(T读取器,Args…Args){
lambda=[reader,args…](IStream&stream){
reader.read(流、参数…);
};
}
typename T::类型读取(IStream和stream){
返回lambda(流);
}
};
testlib/readerWrapper.hpp:8:25:错误:应为“,”before“…”标记
testlib/readerWrapper.hpp:8:25:错误:在“…”标记之前应该有标识符
testlib/readerWrapper.hpp:8:28:错误:参数包未扩展为“…”:
testlib/readerWrapper.hpp:8:28:注意:“args”
g++-4.7给出的编译错误

虽然我不确定第一个例子是否正确,是否应该编译,但我认为第二个和第三个应该编译

我发现,这似乎是不固定的


有解决办法吗?我如何做我想做的事?

这让我想起了一个已知的错误: 它至少影响gcc 4.6.2和4.7.x系列

Clang3.1在处理lambda捕获中的变量时没有问题

也许你可以走老式的路线,将这些东西存储到一个元组中:

#包括
#包括
#包括
////////////////////////////////////
模板结构seq{};
模板结构gens:gens{};
模板结构gens{typedef seq type;};
////////////////////////////////////
模板
结构读取器
{
T型;
};
//特殊实现(驱动类)具有带签名的方法
结构IStream{};
模板
类IntegerReader:公共读取器
{
公众:
T读取(IStream&stream);
T读取(IStream&stream,T最小值,T最大值);
读取(IStream&stream,最小值,最大值,标准::字符串名);
};
模板
类参数恐惧者:公共读取器
{
读卡器;
std::tuple_args;
公众:
参数化恐惧者(T读取器,Args…Args)
:_reader(reader),_args(std::forward(args)…)
{
}
typename T::类型读取(IStream和stream)
{
callFunc(typename gens::type());
}
模板
作废callFunc(seq)
{
func(std::get(_args)…);
}
};
模板
参数化恐惧制造参数化读取器(T读取器,Args…Args)
{
返回参数转发程序(读卡器,标准::转发(args)…);
}
int main(int argc,const char*argv[]
{
读者;
auto-pr=make_参数化_读取器(读取器,“stuff”,3.14,std::string(“你能想到”),std::vector{1,2,3});
}

我会从类模板中删除参数包,使用完美转发和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);
    }
};
模板
类参数恐惧者:公共读取器
{
std::函数lambda;
模板
参数化恐惧者(T读取器、参数和参数)
{
使用名称空间std::占位符;
lambda=std::bind(
std::mem_fn(&Reader::read),
_1,
标准:转发(args);
}
typename T::类型读取(IStream和stream)
{
返回lambda(流);
}
};

您可以通过将参数绑定到lambda而不是捕获它们来解决此问题

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...);
    }
    // ...
};
模板
类参数恐惧者:公共读取器{
std::函数lambda;
模板
参数化恐惧者(T读取器,Args…Args){
lambda=std::bind(
[=](IStream和stream,Args…as){
reader.read(流,as…);
},args;
}
// ...
};
(注:未经测试。)


同样有效的方法是在第二个代码片段中删除
std::bind
,然后像第二个或第三个解决方案一样尝试,这次是使用可变函数模板。也许它能工作,谁知道呢。

Reader::read
可能会过载,使
&Reader::read
变得模棱两可。@Xeo:更新为使用
std::bind
std::bind
默认情况下也会复制所有参数(这不是一件坏事),在创建bind对象时只会减少复制本身的费用。:P@Xeo:根据cppreference,参数可以被移动。@Xeo:read的
可能过载的观点很好(顺便说一句,您更改了注释)。在这种情况下,这确实不起作用。问题是我想要与g++4.7兼容。我去看看图普
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);
    }
};
ParametrizedReader(T reader, Args... args){
    lambda = std::bind(
        [=](IStream& stream, Args... as){
            reader.read(stream, as...);
        }, args...);
}
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...);
    }
    // ...
};