2012-10-05 138 views
4

我有模板類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

雖然我我不確定第一個例子le是正確的,應該編譯,我相信第二和第三個應該。我發現this bug,這似乎是不固定的。

是否有解決方法,我該怎麼做我想要的?

回答

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,然後像第二個或第三個解決方案一樣嘗試,這次使用可變參數函數模板。也許它有效,誰知道。

+0

這個解決方法可行,謝謝 – RiaD

3

這讓我想起了一個已知的bug: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 }); 
} 
+0

問題是我想與g ++ 4.7兼容。我將看看元組謝謝 – RiaD

+0

如果我不想在'Reader'接口中使用元組,我如何在'read'中將'tuple'解包到arg列表? – RiaD

+0

@RiaD我已經更新了使用'索引'技巧演示這個答案(例如從** [這個答案](http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call- a-matching-function-pointer)**) – sehe

0

我從類模板掉落參數時,用完美的轉發和std ::綁定。

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); 
    } 
}; 
+0

'Reader :: read'可能被重載,使&Reader :: read'模糊 – Xeo

+0

@Xeo:已更新爲使用'std :: bind'代替 –

+0

'std :: bind'默認複製所有參數(不是這是一件壞事),你只是在創建綁定對象時減少複製本身的費用:P – Xeo

相關問題