Как создать псевдоним функции шаблона внутри класса шаблона - PullRequest
1 голос
/ 05 августа 2020

Мне нужно реализовать 2 функции внутри шаблонного класса, где обе функции делают похожие вещи, но не все одинаково. Мое предложенное решение заключалось в том, чтобы использовать if constexpr в одной функции-шаблоне, а затем иметь псевдоним для каждой функции:

template <typename T>
class MyClass
{
private:
   template <bool test>
   void TestFunc()
   {
      if constexpr(test)
      {
         // Do something
      }
      else
      {
         // Do other stuff
      }
   }
public:
   ?????? TestTrue = TestFunc<true>;
   ?????? TestFalse = TestFunc<false>;
}

Я пытаюсь выяснить, что должно go, где знаки вопроса , пока что using, auto и const auto не работают. Я хочу, чтобы пользователь мог вызывать TestTrue() и TestFalse() напрямую из объекта класса.

Ответы [ 3 ]

6 голосов
/ 05 августа 2020

Вы могли бы сделать:

void TestTrue() { TestFunc<true>(); }
void TestFalse() { TestFunc<false>(); }

Я не думаю, что есть лучший способ.

1 голос
/ 05 августа 2020

Для полноты, вот уродливый способ.

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

using MemberTestFunction = void (MyClass::*)();

Затем мы можем получить указатели на true и false специализации TestFunc следующим образом:

template <typename T>
class MyClass
{
    // ...
    constexpr static MemberTestFunction TestTrue = &MyClass::TestFunc<true>;

    constexpr static MemberTestFunction TestFalse = &MyClass::TestFunc<false>;
};

Если вы не знакомы с указателями на функции-члены, синтаксис для вызова TestTrue и TestFalse может выглядеть довольно странно. Если вы находитесь внутри функции-члена, вы можете вызывать эти функции либо с помощью оператора ->*, либо с помощью std::invoke (C ++ 17) из <functional>:

template <typename T>
class MyClass
{
    // ...
    void foo() {
        // Direct call with pointer.
        (this->*TestTrue)();
        // Call using std::invoke.
        std::invoke(TestTrue, this);

    }
};

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

MyClass<nullptr_t> x;

// Using type deducation.
(x.*decltype(x)::TestTrue)();

// Using fully qualified name.
(x.*MyClass<nullptr_t>::TestTrue)();

// Using std::invoke (with type deducation).
std::invoke(decltype(x)::TestTrue, x);

Само собой разумеется, что это излишне непонятный способ выполнения любой простой задачи. Я бы не рекомендовал использовать эту технику для создания новых функций (как предлагал HolyBlackCat) или просто называть TestFunc<true>() и TestFunc<false>() явно на месте вызова.

0 голосов
/ 05 августа 2020

Преобразовать функцию TestFunc в функтор:

#include <iostream>

template <typename T>
class MyClass
{
 private:
  template <bool test>
  struct TestFunc
  {
    void operator()() {
      if constexpr(test)
      {
        std::cout << "TestTrue\n";
      }
      else
      {
        std::cout << "TestFalse\n";
      }
    }
  };
 public:
  TestFunc<true> TestTrue;
  TestFunc<false> TestFalse;
};

int main()
{
  MyClass<int> myClass;
  myClass.TestTrue();
  myClass.TestFalse();
}
...