我有一系列不应该连续的数字。让我们说5,2,3,我希望它们映射到数组索引(5 - > 0,2 - > 1,3 - > 2)。这是我的代码,对我来说似乎是正确的。
template<size_t Index, int ...Values>
struct indexer;
template<size_t Index>
struct indexer<Index> { };
template<size_t Index, int T, int ...Rest>
struct indexer<Index, T, Rest...> :
public indexer<Index + 1, Rest...>
{
template<int Value> size_t get();
template<> size_t get<T>() { return Index; }
};
// this class (should) maps Values... to 0,1,2...
template<int ...Values>
struct mapper :
public indexer<0, Values...>
{ };
现在我可以致电:
mapper<5, 2, 3> m;
m.get<5>(); // returns 0 as expected
m.get<2>(); // does not compile
错误1错误LNK2019:未解析的外部符号&#34; public:unsigned int __thiscall indexer&lt; 0,5,2,3&gt; :: get&lt; 2&gt;(void)&#34;函数_main C中引用了(?? $ get @ $ 01 @?$ indexer @ $ 0A @ $ 04 $ 01 $ 02 @@ QAEIXZ):... \ ATL.Console \ main.obj ATL.Console
有人能解释一下是什么错吗?似乎m没有函数get&lt; 2&gt;(),但为什么?
答案 0 :(得分:1)
C ++ 11不允许在类范围内进行显式特化。这个声明:
template<int Value> size_t get(); // primary template
template<> size_t get<T>() { return Index; } // <-- this one
是非法的,只有在语言扩展时才接受在MSVC ++中。
此外,它可能不会做你想要的:
template<int Value> size_t get();
这声明了一个成员函数模板。通过声明名为get
的成员,可以隐藏在任何基类中声明的具有相同名称的所有成员。
然后,明确的专业化:
template<> size_t get<T>() { return Index; }
表示类似的东西(如果它是合法的):如果重载决策选择之前声明该行的主模板get
,并且传递给该成员函数模板的模板参数等同于模板参数{{1在类模板中,这里是您将使用的函数的定义(而不是主成员函数模板的定义)。
函数模板的显式特化为函数模板提供了另一种定义。它本身不是一个函数(模板),并且不参与(本身)重载决策。
当然,如果重载决策选择此成员函数模板,但模板参数条件不成立(= T
时),则使用主模板的定义。但主模板没有定义!因此链接器错误。
以下是您可以这样做的方法:
value != T
当然,现在有许多冗余的#include <cstddef> // for std::size_t
#include <type_traits> // for std::integral_constant
template<size_t Index, int ...Values>
struct indexer;
template<size_t Index>
struct indexer<Index>
{
// provide a dummy to allow simple overloading via a using-declaration
// if you see a linker error here, then Value could not be found
template<int Value>
size_t get(std::integral_constant<int, Value>);
// it would be nice to provide a definition for the template above,
// containing a `static_assert` for a nice compile-time error message,
// but I'm not sure on what to assert.
};
template<size_t Index, int T, int ...Rest>
struct indexer<Index, T, Rest...> :
public indexer<Index + 1, Rest...>
{
template<int Value>
size_t get()
{
return get(std::integral_constant<int, Value>());
}
// a using-declaration to allow overloading
using indexer<Index + 1, Rest...>::get;
size_t get(std::integral_constant<int, T>)
{ return Index; }
};
// this class (should) maps Values... to 0,1,2...
template<int ...Values>
struct mapper :
public indexer<0, Values...>
{};
成员函数模板(所有这些成员函数都可以是get(void)
,顺便说一句。)。因此,您可以将其移至static
或甚至提供非成员函数。