Как уменьшить дублирование при написании признаков для ссылочного и не ссылочного типов, когда признаки одинаковы - PullRequest
4 голосов
/ 02 мая 2019

у меня например

#include <iostream>

template <typename T>
struct Base {};

template <>
struct Base<std::string> {
  static const int value = true;
};

template <>
struct Base<std::string &> {
  static const int value = true;
};

int main() {
  bool a = Base<std::string>::value;
  bool b = Base<std::string &>::value;

  std::cout << a << b << std::endl;
}

https://godbolt.org/z/0NpYxB

Примечание. У меня есть две идентичные специализации, и я хотел бы сократить их до одной. Я знаю два решения, которые я предпочел бы не делать.

(1) Удалить ссылку на сайте вызова, чтобы требовалась только одна специализация.

(2) Создайте базовый класс и унаследуйте ссылку и без ссылки версии из этого.

Есть ли третий вариант, когда специализация является общей для ссылочных и не ссылочных типов?

Требуются решения C ++ 11.

Ответы [ 3 ]

3 голосов
/ 02 мая 2019

1) Кажется нормально:

template <typename T>
struct BaseImpl {};

template <>
struct BaseImpl<std::string> {
  static const int value = true;
};

template <typename T>
using Base = BaseImpl<typename std::remove_reference<T>::type>;

2) кажется более многословным

template <typename T>
struct BaseImpl {};

template <>
struct BaseImpl<std::string> {
  static const int value = true;
};

template <typename T>
struct Base : BaseImpl<T> {}; // or directly BaseImpl<std::remove_reference_t<T>>

template <typename T>
struct Base<T&> : BaseImpl<T> {};

3) Аналогично 2), менее многословно, но может быть более сложным

template <typename T>
struct Base : Base<T&> {};

template <typename T>
struct Base<T&> {};

template <>
struct Base : Base<std::string> {
    static const int value = true;
};

1) кажется более читабельным и простым в реализации.

2 голосов
/ 02 мая 2019

Вы можете выполнить проверку в контексте SFINAE:

// type trait to remove the lvalue-reference
template< class T > struct remove_lvalue_reference      {typedef T type;};
template< class T > struct remove_lvalue_reference<T&>  {typedef T type;};

template <typename T>
using remove_lvalue_reference_t = typename remove_lvalue_reference<T>::type;

template <typename T, typename = void>
struct Base {};

// valid when T is std::string and std::string&
template <typename T>
struct Base<T, typename std::enable_if<std::is_same<std::string, remove_lvalue_reference_t<T>>::value>::type> {
  static const int value = true;
};

ЖИТЬ

2 голосов
/ 02 мая 2019

С enable_if немного тяжело, но я не думаю, что есть лучший способ.

#include <iostream>
#include <type_traits>

template <typename T, typename Enable = void>
struct Base {};


template <typename T>
struct Base<
    T,
    typename std::enable_if< 
       std::is_same<typename std::decay<T>::type, std::string>::value
    >::type 
>
{
  static const int value = true;
};

int main() {
  bool a = Base<std::string>::value;
  bool b = Base<std::string &>::value;

  std::cout << a << b << std::endl;
}

https://godbolt.org/z/98vzFN

...