传递初始化列表时,变量模板参数推导失败

时间:2013-04-01 14:49:58

标签: c++ gcc c++11 variadic-templates initializer-list

Bar拥有std::vector std::pairstd::arrayFooValueAdaptorFooValueAdaptorint隐式将bool转换为FooValueBar::addEntries,这在这个人为的例子中毫无意义,但在我的应用中却是完美无缺的。 我实现了一个方便函数#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; } ,用于一次添加多个条目,但是使用两个以上的参数调用它无法使用GCC 4.8.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

编译器错误消息:

{{1}}

我如何帮助编译器的演绎?

1 个答案:

答案 0 :(得分: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",但这需要一些时间。