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>;
答案 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();
在任何一种情况下都会驯服链接器。
您尝试的是明确的专业化,虽然使用了不同的机制,但确实解决了这个问题。