代码之家  ›  专栏  ›  技术社区  ›  user7860670

在模板类未专用化时为模板类的模板成员函数编写专用化的解决方法

  •  1
  • user7860670  · 技术社区  · 6 年前

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

    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
    

    我不确定这里的语法,但似乎问题是由friend声明引起的。如果我做 doo_impl 功能公开和删除 friend 声明它与clang和gcc编译得很好,但vc仍然抱怨。所以我想找一些建议来解决这个问题,或者找一个更简单的解决方法。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Jarod42    6 年前

    添加一个可以专门化的层,可能会导致枚举过载:

    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