变量模板+ std :: map的通用lambdas

时间:2014-01-17 14:20:58

标签: c++ c++14

answer to C++14 Variable Templates: what is the purpose? Any usage example?提出了变量模板+通用lambdas的用法示例,如下所示:

void some_func() {
    template<typename T>
    std::map<int, T> storage;

    auto store = []<typename T>(int key, const T& value) { storage<T>.insert(key, value) };

    store(0, 2);
    store(1, "Hello"s);
    store(2, 0.7);

    // All three values are stored in a different map, according to their type. 
}

不幸的是它没有编译,所以我试图修复&#34;到目前为止,这是我的尝试。

#include <map>

template<typename T>
std::map<int, T> storage;

void some_func() {

    auto store = [](int key, const auto& value) { storage<decltype(value)>.insert(key, value); };

    store(0, 2);
    store(1, std::string("Hello"));
    store(2, 0.7);
}

错误消息是:

main.cpp:7:76: error: no matching member function for call to 'insert'

    auto store = [](int key, const auto& value) { storage<decltype(value)>.insert(key, value); };
                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
main.cpp:10:10: note: in instantiation of function template specialization 'some_func()::<anonymous class>::operator()<std::basic_string<char> >' requested here

    store(1, std::string("Hello"));

当您像所有模板一样实例化变量模板时,每个变量将是不同的类型。理论是auto并不是针对每种类型推导出来的,而是最初只有一种类型(双重)。因此代码无效。即使 可以工作,存储的每个实例都会引用不同的变量。

如何重写此代码以实现原始意图?


修改我在编辑中犯了一个小错误(请参阅修订历史记录,以避免文字墙。)decltype(pair)应为decltype(pair.second),因为只有一个模板参数storage

#include <map>

template <typename T>
std::map<int, T> storage;

void some_func() {
    auto store = [&](auto pair) { storage<decltype(pair.second)>.insert(pair); };

    store(std::pair<int, int>(0, 1));
    store(std::pair<int, std::string>(1, "Hello!"));
    store(std::pair<int, int>(2, 3));
}

int main()
{
}

现在有链接器错误。

/tmp/main-5f1f7c.o: In function `some_func()':
main.cpp:(.text+0x1a): undefined reference to `storage<int>'
main.cpp:(.text+0x43): undefined reference to `storage<std::string>'
main.cpp:(.text+0x74): undefined reference to `storage<int>'

为了修复链接器错误,我认为你需要显式实例化参数? (我甚至不确定这是否是正确的术语。)

template <typename T>
std::map<int, T> storage;

template <>
std::map<int, int> storage<int>;

template <>
std::map<int, std::string> storage<std::string>;

Live Example

1 个答案:

答案 0 :(得分:3)

template<typename T>
std::map<int, T> storage;

这是一个声明,很像例如template<typename T> class foo;。无论如何我们还需要一个,我们也可以从定义中获益:

template<typename T>
std::map<int, T> storage {};

然而,这并没有消除链接器错误,这表明隐式实例化存在一个突出的错误。为了说服自己,我们可以通过各种方式触发实例化:

    明确地
  • ,看起来像

    // namespace scope, same as storage
    template /* sic */ std::map<int, int>         storage<int>;
    template           std::map<int, std::string> storage<std::string>;
    
  • 隐含地,通过在main

    中添加以下内容
    storage<int>.size();
    storage<std::string>.size();
    

在任何一种情况下都会驯服链接器。

您尝试的是明确的专业化,虽然使用了不同的机制,但确实解决了这个问题。