Обходной путь для написания специализации для функции-члена шаблона класса шаблона, когда класс шаблона не специализирован - PullRequest
0 голосов
/ 06 ноября 2018

Я конвертирую существующий класс, который имеет набор функций-членов шаблона, специализирующихся на значениях перечислителя в классе, в класс шаблона. Однако язык не позволяет специализовать функции-члены шаблона без специализации шаблона класса, поэтому это не работает:

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 дает :

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 дает :

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 голосов
/ 07 ноября 2018

Добавьте слой, который вы можете специализировать, возможно, с перегрузкой для вашего enum:

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;
}

Демо

...