Функциональные эквиваленты C++ STL для метапрограммирования

Существуют ли constexpr или другие эквиваленты времени компиляции для функциональных возможностей STL и других библиотек для использования с метапрограммированием? В частности, я пытаюсь написать несколько метапрограмм, которые используют SFINAE для оценки некоторых условных выражений и создания соответствующих типов. Пример:

template<int A, int B>
enable_if_t<(A < B)> my_func() {// do something 
}

template<int A, int B>
enable_if_t<!(A < B)> my_func() {// do nothing 
}

В идеале я хотел бы, чтобы пользователь мог передавать компаратор (например, std::less<int>), а не жестко кодировать его в <. Итак, что-то вроде:

template<int A, int B, class comp = std::less<int>>
enable_if_t<comp(A, B)> my_func() {// do something 
}

template<int A, int B, class comp = std::less<int>>
enable_if_t<comp(A, B)> my_func() {// do nothing 
}

Однако, поскольку функциональные объекты не являются константными выражениями, они не оцениваются во время компиляции, поэтому это не работает. Каким будет правильный способ реализовать что-то подобное?


person Ammar Husain    schedule 08.04.2016    source источник
comment
Это не работает. Компилятор жалуется: аргумент шаблона нетипа не является константным выражением   -  person Ammar Husain    schedule 08.04.2016
comment
enable_if_t определяется только в c++14. Как вы ожидаете, что это будет работать с С++ 11? Вы сами это определили?   -  person hlscalon    schedule 08.04.2016


Ответы (1)


std::less<int>(int, int) не является конструктором для std::less. Единственным конструктором для std::less является () (я предпочитаю использовать {}, потому что это дает понять, что я что-то конструирую).

Начиная с С++ 14, он имеет constexpr operator(), который (если < для вовлеченных типов равен constexpr) может быть оценен во время компиляции.

Таким образом:

template<int A, int B, class comp = std::less<int>>
enable_if_t<comp{}(A, B)> my_func() {// do something 
}

template<int A, int B, class comp = std::less<int>>
enable_if_t<!comp{}(A, B)> my_func() {// do nothing 
}

должно сработать.

In C++11

namespace notstd {
  template<class T=void>
  struct less {
    constexpr bool operator()(T const& lhs, T const& rhs)const{
      return lhs<rhs;
    }
  };
  template<>
  struct less<void> {
    template<class T, class U>
    constexpr bool operator()(T const& lhs, U const& rhs)const{
      return lhs<rhs;
    }
    // maybe also add this:
    //struct is_transparent {};
  }
}

(при условии, что ваш < в вашей системе является полным порядком указателей) должен работать (заменив std::less<T> на notstd::less<T>).

person Yakk - Adam Nevraumont    schedule 08.04.2016
comment
Извините, только что обновил исходный вопрос, мне все еще нужно быть на С++ 11. - person Ammar Husain; 08.04.2016
comment
И если вы застряли на С++ 11, вы все равно можете определить свои собственные constexpr функции сравнения/функторы/что угодно... :-) - person jotik; 08.04.2016
comment
последнее следует отрицать, !comp{}(A, B) - person Piotr Skotnicki; 08.04.2016
comment
Добавлена ​​реализация @AmmarHusain C++11 notstd::less. - person Yakk - Adam Nevraumont; 08.04.2016