我有模板类Reader
template<typename T>
class Reader{
typedef T type;
};
特殊实现(derrived类)具有签名
的方法 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
给出的编译错误虽然我不确定第一个例子是否正确并且应该编译,但我相信第二个和第三个应该是。
我找到this bug,似乎没有修复。
是否有解决方法,我该怎样做我想要的?
答案 0 :(得分:4)
您可以通过将参数绑定到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::bind
放在第二个代码段中,尝试使用第二个或第三个解决方案,这次使用可变参数函数模板。也许它有效,谁知道。
答案 1 :(得分:3)
这让我想起了一个已知的错误:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933 它至少影响gcc 4.6.2和4.7.x系列。
Clang 3.1在处理lambda捕获中的可变参数时没有问题。
也许你可以走老式的路线并把东西存放到一个元组中: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 });
}
答案 2 :(得分: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);
}
};