Ответ 1
Ваш код недействителен. Компилятор (GCC7.1 для меня) предоставляет полезную ошибку, которая позволяет решить эту проблему.
Вопрос:
...\main.cpp|19|note: 'detail::is_value<int, true>' is not literal because:|
...\main.cpp|19|note: 'detail::is_value<int, true>' has a non-trivial destructor|
Причина detail::is_value
не имеет тривиального деструктора из-за члена std::function<>
; std::function<>
может выполнять динамическое распределение памяти (среди других причин), поэтому это не тривиально. Вы должны заменить его на тривиально разрушаемый тип; Я представляю простое решение ниже.
Примечание. Даже если std::function<>
было тривиально разрушаемым, его operator()
, похоже, не объявляется как constexpr
(см. http://en.cppreference.com/w/cpp/utility/functional/function/operator()), поэтому он не будет работать.
Пример рабочего кода (при необходимости приспособитесь):
#include <iostream>
#include <functional>
namespace detail
{
// Reason to use an enum class rahter than just an int is so as to ensure
// there will not be any clashes resulting in an ambigious overload.
enum class enabler
{
enabled
};
}
#define ENABLE_IF(...) std::enable_if_t<(__VA_ARGS__), detail::enabler> = detail::enabler::enabled
#define ENABLE_IF_DEFINITION(...) std::enable_if_t<(__VA_ARGS__), detail::enabler>
namespace detail
{
// notice the new template parameter F
template <typename T, typename F, bool IS_BUILTIN>
class is_value
{
T item_to_find;
F predicate;
public:
constexpr is_value(T item_to_find, F predicate)
: item_to_find(item_to_find)
, predicate(predicate)
{}
constexpr bool one_of() const
{
return false;
}
template <typename T1, typename...Ts>
constexpr bool one_of(T1 const & item, Ts const&...args) const
{
return predicate(item_to_find, item) ? true : one_of(args...);
}
};
template <typename T, typename F>
class is_value<T, F, false>
{
T const& item_to_find;
F predicate;
public:
constexpr is_value(T const& item_to_find, F predicate)
: item_to_find(item_to_find)
, predicate(predicate)
{}
constexpr bool one_of() const
{
return false;
}
template <typename T1, typename...Ts>
constexpr bool one_of(T1 const& item, Ts const&... args) const
{
return predicate(item_to_find, item) ? true : one_of(args...);
}
};
}
// sample predicate
template<class T>
struct default_compare
{
constexpr bool operator()(T const& lhs, T const& rhs) const
noexcept(noexcept(std::declval<T const&>() == std::declval<T const&>()))
{
return lhs == rhs;
}
};
// Find if a value is one of one of the values in the variadic parameter list.
// There is one overload for builtin types and one for classes. This is so
// that you can use builtins for template parameters.
//
// Complexity is O(n).
//
// Usage:
//
// if (is_value(1).one_of(3, 2, 1)) { /* do something */ }
//
template <typename T, typename F = default_compare<T>, ENABLE_IF(!std::is_class<T>::value)>
constexpr auto const is_value(T item_to_find, F predicate = {})
{
return detail::is_value<T, F, true>(item_to_find, predicate);
}
template <typename T, typename F = default_compare<T>, ENABLE_IF(std::is_class<T>::value)>
constexpr auto const is_value(T const& item_to_find, F predicate = {})
{
return detail::is_value<T, F, false>(item_to_find, predicate);
}
template <int I, ENABLE_IF(is_value(I).one_of(3,2,1))>
void fn()
{
}
int main()
{
fn<3>();
std::cout << "Hello, world!\n" << is_value(3).one_of(3,2,1);
}