/ / Як я можу використовувати Boost.Hana, щоб визначити, чи має функтор оператора виклику, який можна викликати з певним аргументом шаблону? - C + + 14, boost-hana

Як я можу використовувати Boost.Hana, щоб визначити, чи має функтор оператор виклику, який може бути викликаний з певним аргументом шаблону? - C + + 14, boost-hana

У моєму додатку хочеться визначити, чи є довільний тип функтора на час компіляції Func має оператор нульового виклику, який може бути викликаний з даним явним аргументом шаблону T. Виходячи з попередньої відповіді, що я знайшов, Я прийшов до наступного:

#include <boost/hana.hpp>
#include <iostream>
#include <type_traits>

namespace hana = boost::hana;

namespace detail
{
template <typename T>
auto can_call = hana::is_valid([](auto &&f) ->
decltype(f.template operator()<T>()) { });
}

template <typename Func, typename T>
constexpr auto can_call() ->
decltype(detail::can_call<typename std::remove_reference<T>::type>(
std::declval<Func>())) { return {}; }

struct foo
{
template <typename T, typename =
std::enable_if_t<!std::is_same<T, char>::value>>
void operator()() const { }
};

int main()
{
std::cout << "char: " << can_call<foo, char>() << std::endl;
std::cout << "int: " << can_call<foo, int>() << std::endl;
}

Я очікую, що цей приклад буде надруковано:

char: 0
int: 1

З моменту char Тип аргументу шаблону явно enable_ifвийшов у foo. Я спробував наступні компілятори:

  • Apple clang v8.0.0: приклад складається і працює як очікується.
  • mainline clang v3.9.1 + (через Wandbox): приклад складається і працює як очікується.
  • mainline clang v3.6.0 - v3.8.1 (через Wandbox): компілятор помирає з внутрішньою помилкою.
  • g ++ 7.0, 20170410 (через Wandbox): компіляція не працює з наступними помилками:

    dd.cc: In instantiation of ‘auto detail::can_call<char>’:
    dd.cc:15:14:   required by substitution of ‘template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call() [with Func = foo; T = char]’
    dd.cc:25:50:   required from here
    dd.cc:10:10: error: ‘auto detail::can_call<char>’ has incomplete type
    auto can_call = hana::is_valid([](auto &&f) -> decltype(f.template operator()<T>()) { });
    ^~~~~~~~
    dd.cc: In function ‘int main()’:
    dd.cc:25:50: error: no matching function for call to ‘can_call<foo, char>()’
    std::cout << "char: " << can_call<foo, char>() << std::endl;
    ^
    dd.cc:14:16: note: candidate: template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call()
    constexpr auto can_call() ->
    ^~~~~~~~
    dd.cc:14:16: note:   substitution of deduced template arguments resulted in errors seen above
    dd.cc: In instantiation of ‘auto detail::can_call<int>’:
    dd.cc:15:14:   required by substitution of ‘template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call() [with Func = foo; T = int]’
    dd.cc:26:48:   required from here
    dd.cc:10:10: error: ‘auto detail::can_call<int>’ has incomplete type
    auto can_call = hana::is_valid([](auto &&f) -> decltype(f.template operator()<T>()) { });
    ^~~~~~~~
    dd.cc:26:48: error: no matching function for call to ‘can_call<foo, int>()’
    std::cout << "int: " << can_call<foo, int>() << std::endl;
    ^
    dd.cc:14:16: note: candidate: template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call()
    constexpr auto can_call() ->
    ^~~~~~~~
    dd.cc:14:16: note:   substitution of deduced template arguments resulted in errors seen above
    

Здається, мені не подобається моє використання hana::is_valid() щоб визначити, чи існує вказаний оператор. Однак, я думаю, що спосіб, яким він використовується, відповідає його призначеному використанню.

Це помилка в gcc, більш м'якареалізація в сучасних версіях, або я неправильно реалізував цей тип перевірки? Схоже, що це, безумовно, знаходиться в рульовій хана, я просто намагаюся загорнути голову навколо своєї нової моделі constexpr метапрограмування

Відповіді:

2 для відповіді № 1

Ось обхідний шлях, який використовує struct "functor" замість лямбда та додатковий шар неявки для типу is_valid Наприклад, заспокоїти GCC.

namespace detail
{
template <typename T>
struct check_can_call {
template <typename F>
constexpr auto operator()(F&& f) ->
decltype(f.template operator()<T>()) { }
};

template <typename T>
using is_call_valid = decltype(hana::is_valid(check_can_call<T>{}));

template <typename T>
constexpr is_call_valid<T> can_call{};
}