Концептуальные перегрузки функций-членов шаблона - PullRequest
0 голосов
/ 20 января 2019

Пример того, как мы будем перегружать функции-члены шаблона шаблонного класса при отсутствии концепций, показан в этом фрагменте .

Теперь примерно пытаюсь написать нечто подобное, используя понятия:

template <typename T>
struct Foo{
    Foo(T elem): elem_(elem) {}
    template <typename U = T>  requires Integral<U>
    int get() {
        return -1;
    }
    template <typename U = T>  requires Bool<U>
    int get() {
        return 0;
    }
    T elem_;
};

Два способа организовать это:
1. Хранение декларации и определения вместе: это работает как ожидалось. Фрагмент кода
2. Разделение объявления и определения: не компилируется ( Фрагмент кода )

Учитывая вышеизложенное, у меня было два вопроса:
1. Причина, по которой template <typename T> template <typename U=T> member_fn... изначально была необходима из-за SFINAE. Нет ли способа избежать этого с помощью Concepts для дальнейшего упрощения кода?
2. Как правильно разделить объявление и определение?

1 Ответ

0 голосов
/ 20 января 2019

Прежде всего, ограничение шаблона должно быть одинаковым в объявлении и определении (см. [temp.over.link] / 6 ). В противном случае компилятор не сможет определить, к какому объявлению относится определение.

Итак, этот код скомпилируется:

template <typename T>
struct Foo{

  Foo(T elem): elem_(elem) {}

  template <typename U = T>  requires Integral<U>
  int get() ;

  template <typename U = T>  requires Bool<U>
  int get() ;

  T elem_;
  };

template<class T>
template<class U> requires Integral<U> 
int Foo<T>::get() {
  return -1;
  }
template<class T>
template<class U> requires Bool<U>
int Foo<T>::get()  {
  return 0;
  }

Тогда трюк с задержкой проверки концепции, использующий аргумент шаблона по умолчанию, не требуется, поскольку можно связать ограничение с функцией в ее завершающем требовании :

template <typename T>
struct Foo{

  Foo(T elem): elem_(elem) {}


  int get() requires Integral<T>;

  int get() requires Bool<T>;

  T elem_;
  };

template<class T>
int Foo<T>::get() requires Integral<T> {
  return -1;
  }

template<class T>
int Foo<T>::get() requires Bool<T> {
  return 0;
  }
...