c++ - 变量模板 + std::map 的通用 lambda

标签 c++ c++14

answer to C++14 Variable Templates: what is the purpose? Any usage example?提出了一个变量模板 + 通用 lambda 的用法示例,看起来像这样:

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. 
}

不幸的是它没有编译,所以我试图“修复”它,这是我目前的尝试。

#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 不会针对每种类型推导,但最初只会推导一种类型( double )。因此代码无效。即使这可以工作,存储的每个实例化都将引用不同的变量。

如何重写这段代码才能达到初衷?


编辑 我在编辑中犯了一个小错误(查看修订历史以避免文本墙。)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

最佳答案

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();
    

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

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

关于c++ - 变量模板 + std::map 的通用 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21188052/

相关文章:

c++ - 初始化器列表和运算符的 RHS

c++ - 附加到 Qt Creator 中正在运行的进程后如何查看控制台输出?

c++ - ALSA:如何判断声音何时播放完毕

c++ - 如何为Windows Office 文档之类的文件添加属性?

c++ - 如何使用c++11/14来简化这个实现

c++ - 如果浮点范围更大,通过浮点的往返是否总是定义行为?

c++ - 将互斥锁绑定(bind)到对象

c++ - 从字符串输入中删除特定单词

c++ - 通用 lambda 可以没有参数吗?

c++ - 为什么我不能对 std::ofstream 使用 operator bool()