为每个模板(int)形参向类中添加方法

Add method to class for each template (int) parameter

本文关键字:形参 方法 添加 int      更新时间:2023-10-16

我有一个数列,它不应该是连续的。比如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:未解析的外部符号"public: unsigned int __thiscall indexer<0,5,2,3>::get<2>(void)"($get@$01@?$indexer@$0A@$04$01$02@@QAEIXZ)在函数_main C:…ATL.Consolemain中引用。obj ATL。控制台

谁能解释一下怎么回事?似乎m没有函数get<2>(),但为什么?

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,并且传递给该成员函数模板的模板形参等于类模板的模板形参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)。因此,您可以将其移动到mapper中,甚至可以提供非成员函数。