当模板类不专门化时,为模板类的模板成员函数编写专门化的解决方法

时间:2018-11-06 18:09:39

标签: c++ templates c++17 specialization

我正在将具有一组专门用于类内枚举器值的模板成员函数的现有类转换为模板类。但是,语言不允许在没有模板类专业化的情况下对模板成员函数进行专业化处理,因此这是行不通的:

template <typename x_Dummy>
class t_Test
{
public:
    enum t_KindId{first, second};

public:
    template <t_KindId x_kind> auto doo() -> void;
};

template <typename x_Dummy>
template<>
inline auto t_Test<x_Dummy>::doo<t_Test<x_Dummy>::t_KindId::first>() -> void
{
    return;
}

因此我想出了解决方法,可以将模板函数主体放在内部模板类的类内部分专业化的静态函数中。但是,这种方法也不起作用:

template <typename x_Dummy>
class t_Test
{
public:
    enum class t_KindId{first, second};

public:
    template <t_KindId x_kind> auto doo() -> void;

private:
    template <t_KindId x_kind, typename xx_Dummy = void>
    class t_DooImpl;

private:
    template <typename xx_Dummy>
    class t_DooImpl<t_KindId::first, xx_Dummy> final
    {
        friend auto t_Test<x_Dummy>::doo<t_KindId::first>() -> void;

    private:
        static inline auto doo_impl([[maybe_unused]] t_Test<x_Dummy> & self) -> void
        {
            return;
        }
    };
};

template <typename x_Dummy>
template <typename t_Test<x_Dummy>::t_KindId x_kind>
inline auto t_Test<x_Dummy>::doo(void) -> void
{
    return t_DooImpl<x_kind>::doo_impl(*this);
}

int main()
{
    using t_Test = t_Test<int>;
    t_Test t{};
    t.doo<t_Test::t_KindId::first>();
    return 0;
}

clang gives

prog.cc:30:9: error: no candidate function template was found for dependent friend function template specialization
        doo<t_KindId::first>(void) -> void;
        ^
prog.cc:52:26: error: incomplete definition of type 't_Test<int>::t_DooImpl<t_Test<int>::t_KindId::first, void>'
        return t_DooImpl<x_kind>::doo_impl(*this);
               ~~~~~~~~~~~~~~~~~^~
prog.cc:59:4: note: in instantiation of function template specialization 't_Test<int>::doo<t_Test<int>::t_KindId::first>' requested here
        t.doo<t_Test::t_KindId::first>();
          ^
2 errors generated.

gcc gives

prog.cc: In instantiation of 'class t_Test<int>::t_DooImpl<(t_Test<int>::t_KindId)0, void>':
prog.cc:52:36:   required from 'void t_Test<x_Dummy>::doo() [with t_Test<x_Dummy>::t_KindId x_kind = (t_Test<int>::t_KindId)0; x_Dummy = int]'
prog.cc:59:33:   required from here
prog.cc:29:15: error: 'doo' was not declared in this scope
   friend auto t_Test<x_Dummy>::
               ^~~~~~~~~~~~~~~
prog.cc:29:15: note: suggested alternative: 'bool'
   friend auto t_Test<x_Dummy>::
               ^~~~~~~~~~~~~~~
               bool
prog.cc: In instantiation of 'void t_Test<x_Dummy>::doo() [with t_Test<x_Dummy>::t_KindId x_kind = (t_Test<int>::t_KindId)0; x_Dummy = int]':
prog.cc:59:33:   required from here
prog.cc:52:36: error: 'static void t_Test<x_Dummy>::t_DooImpl<t_Test<x_Dummy>::t_KindId::first, xx_Dummy>::doo_impl(t_Test<x_Dummy>&) [with xx_Dummy = void; x_Dummy = int]' is private within this context
  return t_DooImpl<x_kind>::doo_impl(*this);
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
prog.cc:33:3: note: declared private here
   doo_impl
   ^~~~~~~~

vc ++给出:

warning C4348: 't_Test<int>::t_DooImpl': redefinition of default parameter: parameter 2
note: see declaration of 't_Test<int>::t_DooImpl'
note: see reference to class template instantiation 't_Test<int>' being compiled
error C2027: use of undefined type 't_Test<int>::t_DooImpl<t_Test<int>::t_KindId::first,void>'
note: see declaration of 't_Test<int>::t_DooImpl<t_Test<int>::t_KindId::first,void>'
note: see reference to function template instantiation 'void t_Test<int>::doo<t_Test<int>::t_KindId::first>(void)' being compiled
note: see reference to function template instantiation 'void t_Test<int>::doo<t_Test<int>::t_KindId::first>(void)' being compiled
error C3861: 'doo_impl': identifier not found

我不确定这里的语法,但是似乎问题是由朋友声明引起的。如果我将doo_impl函数设为公开并删除friend声明,则可以用clang和gcc很好地编译,但是vc仍然会抱怨。因此,我正在寻找有关如何解决此问题的建议,或者寻求更简单的解决方法。

1 个答案:

答案 0 :(得分:1)

添加一个可以专门化的图层,可能会给枚举带来重载:

template <typename T>
class t_Test
{
public:
    enum t_KindId {first, second};

public:
    template <t_KindId x_kind> void doo() { doo_impl(std::integral_constant<t_KindId , x_kind>{}); }

private:
    void doo_impl(std::integral_constant<t_KindId , first>);
    void doo_impl(std::integral_constant<t_KindId , second>);
};

然后:

template <typename T>
void t_Test<T>::doo_impl(std::integral_constant<typename t_Test<T>::t_KindId , t_Test<T>::first>)
{
    std::cout << "first" << std::endl;
}

template <typename T>
void t_Test<T>::doo_impl(std::integral_constant<typename t_Test<T>::t_KindId , t_Test<T>::second>)
{
    std::cout << "second" << std::endl;
}

Demo