Variadic template argument output fails when passing initializer lists

Bar contains a std::vector of std::pair of std::array of FooValueAdaptor s. FooValueAdaptor implicitly converts int to bool in FooValue , which makes little sense in this contrived example, but it makes perfect sense in my application. I used the convenience function Bar::addEntries to add multiple entries at the same time, but calling it with more than two arguments cannot be compiled using GCC 4.8.0. See Error Messages below.

 #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; } 

Compiler Error Messages:

 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 

How can I help bring the compiler together?

+4
source share
1 answer

You need to explicitly tell the compiler what you need:

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

and name it as follows:

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

Note the sheer amount of braces, but I think that this is actually the only correct syntax. Fewer parentheses are accepted by both GCC 4.8 and Clang 3.2, but Clang gives a lot of warnings, the above fixes. Some people are already working on a โ€œfixโ€ , but it will take some time.

+2
source

All Articles