为每个模板(int)参数添加类的方法

时间:2014-03-15 16:33:52

标签: c++ c++11 variadic-templates

我有一系列不应该连续的数字。让我们说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;(),但为什么?

1 个答案:

答案 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或甚至提供非成员函数。