Специализированные шаблонные классы с пакетами параметров - PullRequest
0 голосов
/ 07 февраля 2020

Я использую наследование с набором классов. Один из дочерних классов принимает std::function(ReturnTy<ParamTypes...>) вместе с ParamTypes аргументами. Сигнатура класса и конструктор выглядят так:

template<class ReturnTy, class... ParamTypes>
class Child : public Interface
{
public:
    Child(ReturnTy default_value, ParamTypes... args)
        : func_set_(false)
        , m_Args(std::make_tuple(std::forward<ParamTypes>(args)...))
        , m_ReturnValue(default_value)
    {}

private:
    bool func_set_;
    std::function<ReturnTy(ParamTypes...)> m_Funciton;
    std::tuple<ParamTypes...> m_Args;
    ReturnTy m_ReturnValue;
};

Моя проблема, когда я хочу специализироваться для случая, когда нет параметров. Кроме того, я также хочу специализироваться для случая, когда ReturnTy=void и есть параметры. Я нашел ответ, который близок к тому, что я ищу здесь , но он не совсем охватывает то, что я пытаюсь сделать, потому что этот вопрос использует целые числа времени компиляции в качестве параметров шаблона, где я использую типы. Это касается и функций вместо классов. Я чувствую, что я близко, но мне просто нужна помощь, чтобы заставить мой код работать.

Для справки, вот что у меня есть для других специализаций (сокращенно):

template<class ReturnTy>
class Child<ReturnTy> : public Interface
{
public:
    Child(ReturnTy default_value)
        : // The same as first class without m_Args
    {}

private:
    // Same as first class without m_Args
};

template<class... ParamTypes>
class Child<void, ParamTypes...> : public Interface
{
public:
    Child(ParamTypes... args)
        : // Same as first class without m_ReturnValue

private:
    // Same as first class without m_ReturnValue
};

Редактировать В частности, проблема связана со следующей строкой кода:

Child<void> obj1(5);

Ответы [ 2 ]

1 голос
/ 07 февраля 2020

Проблема в том, что ваши специализации имеют один и тот же уровень (никто не более специализирован, чем другой), и Child<void> соответствует обоим.

Если вы хотите, чтобы Child<void> соответствовало кейсу Child<ReturnTy> (в противном случае решение простое и элегантное: во второй специализации разделите список ParamTypes... на обязательный тип Par0 и остальные ParamTypes...). Я не вижу простого и элегантного решения.

На данный момент лучшее, что я могу себе представить, это добавить уровень косвенности (добавить класс Child_base), добавив также параметр шаблона, чтобы явно указать желаемое решение.

Может быть, это можно сделать в более простой способ (извините, но в данный момент я могу попробовать с компилятором), но я представляю что-то следующее

template <typename RT, bool, typename ... PTs>
class Child_base : public Interface
{
   // general case (no empy PTs... list and no void return type)
};

template <typename ... PTs>
class Child_base<void, true, PTs...> : public Interface
{
   // case return type is void (also empy PTs... list)
};

template <typename RT>
class Child_base<RT, false> : public Interface
{
   // case return type only, but not void, and empy PTs
};

template <typename RT, typename ... PTs>
class Child 
   : public Child_base<RT, std::is_same_v<void, RT>, PTs...> 
 {
 };

Таким образом, Child<void> наследуется от Child_base<void, true>, что соответствует первой специализации Child_base, но не соответствует второму.

Я предлагаю другой способ использования Child: вместо определения его как класса, производного от Child_base, вы можете попробовать определить его как using псевдоним из Child_base

* 1 027 *

Возможно переименование Child_base с более подходящим именем.

0 голосов
/ 07 февраля 2020

проблема в том, что Child<void> соответствует 2 (частичным) специализациям (где ни одна не является более специализированной, чем другая):

  • template<class ReturnTy> class Child<ReturnTy> с [ReturnTy = void]
  • template<class... ParamTypes> class Child<void, ParamTypes...> с пустой пачкой.

Вам нужна дополнительная специализация:

template<>
class Child<void> : public Interface
{
public:
    Child() = default;

// ....
private:
    std::function<void()> m_Function;
};

Демо

...