2013-04-01 92 views
4

Bar持有std::vectorstd::pair s的std::array s的FooValueAdaptor s。 FooValueAdaptor隱式轉換intboolFooValue,這使得在這個人爲的例子沒有什麼意義,但是非常有意義的我的應用程序。 我實現了一個方便的功能Bar::addEntries可以一次添加多個條目,但有兩個以上的參數調用失敗使用GCC 4.8.0編譯。請參閱下面的錯誤消息。當傳遞初始化列表時,變量模板參數推導失敗

#include <array> 
#include <utility> 
#include <vector> 

enum class FooValue { 
    A, 
    B, 
    C 
}; 

class FooValueAdaptor { 
public: 
    FooValueAdaptor(bool value) 
     : m_value(static_cast<FooValue>(value)) { 
    } 

    FooValueAdaptor(int value) 
     : m_value(static_cast<FooValue>(static_cast<bool>(value))) { 
    } 

    FooValueAdaptor(FooValue value) 
     : m_value(value) { 
    } 

    operator FooValue() { 
     return m_value; 
    } 

    operator bool() { 
     return m_value == FooValue::C; 
    } 

private: 
    FooValue m_value; 
}; 

template<std::size_t nFirst, std::size_t nSecond> 
class Bar { 
public: 
    typedef std::array<FooValueAdaptor, nFirst> First; 
    typedef std::array<FooValueAdaptor, nSecond> Second; 
    typedef std::pair<First, Second> Entry; 

    Bar() 
     : m_table() { 
    } 

    void addEntry(First first, Second second) { 
     m_table.push_back(std::make_pair(first, second)); 
    } 

    template <typename... Args> 
    void addEntries() { 
    } 

    template <typename... Args> 
    void addEntries(First first, Second second, Args... args) { 
     addEntry(first, second); 
     addEntries(args...); 
    } 

private: 
    std::vector<Entry> m_table; 
}; 

int main(int argc, char **argv) { 
    Bar<2, 1> b; 

    b.addEntry({ 0, 0 }, { 0 }); 
    b.addEntries(
     { 0, 1 }, { 0 }, 
     { 1, 0 }, { 0 }, 
     { 1, 1 }, { 1 } 
    ); 

    return 0; 
} 

編譯器錯誤信息:

test.cpp: In function ‘int main(int, char**)’: 
test.cpp:74:2: error: no matching function for call to ‘Bar<2ul, 1ul>::addEntries(<brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>)’ 
); 
^
test.cpp:74:2: note: candidates are: 
test.cpp:53:7: note: template<class ... Args> void Bar<nFirst, nSecond>::addEntries() [with Args = {Args ...}; long unsigned int nFirst = 2ul; long unsigned int nSecond = 1ul] 
    void addEntries() { 
    ^
test.cpp:53:7: note: template argument deduction/substitution failed: 
test.cpp:74:2: note: candidate expects 0 arguments, 6 provided 
); 
^
test.cpp:57:7: note: void Bar<nFirst, nSecond>::addEntries(Bar<nFirst, nSecond>::First, Bar<nFirst, nSecond>::Second, Args ...) [with Args = {}; long unsigned int nFirst = 2ul; long unsigned int nSecond = 1ul; Bar<nFirst, nSecond>::First = std::array<FooValueAdaptor, 2ul>; Bar<nFirst, nSecond>::Second = std::array<FooValueAdaptor, 1ul>] 
    void addEntries(First first, Second second, Args... args) { 
    ^
test.cpp:57:7: note: candidate expects 2 arguments, 6 provided 

我怎麼能幫助編譯器的扣除相處?

+0

爲什麼'addEntries()'是一個模板? –

+4

傳遞* braced-init-list *時根本沒有模板參數推導,因爲這樣的* braced-init-list *實際上並不是一個表達式。 – Xeo

+0

@Xeo謝謝你指出。此鏈接介紹非常詳細:http://en.cppreference.com/w/cpp/language/list_initialization – user2232439

回答

2

您需要明確地告訴編譯器,你需要的東西:

void addEntries(std::initializer_list<std::pair<First, Second>> il) { 
    for(const auto& e : il) { 
     addEntry(e.first,e.second); 
    } 
} 

,並調用它像這樣:

b.addEntry({{ 0, 0 }}, {{ 0 }}); 
b.addEntries({ 
    {{{ 0, 1 }}, {{ 0 }}}, 
    {{{ 1, 0 }}, {{ 0 }}}, 
    {{{ 1, 1 }}, {{ 1 }}} 
}); 

公告大括號的金額巨大,但我覺得上面的其實是唯一正確的語法。 GCC 4.8和Clang 3.2都接受較少的括號,但Clang給出了很多警告,上述修正。有些人已經是working on a "fix",但那需要一些時間。

+0

我是如此渴望嘗試可變參數模板,它從來沒有想過我使用'initializer_list'的'對'。談論沒有看到樹木的木材。 ;) 謝謝。 – user2232439