Проверете дали даден клас има евентуално претоварен оператор за извикване на функция

Чудя се дали би било възможно да се приложи характеристика в C++20, за да се провери дали тип T е такъв, че има евентуално претоварен/евентуално шаблонен оператор за извикване на функция: operator().

// Declaration
template <class T>
struct has_function_call_operator;

// Definition
???  

// Variable template
template <class T>
inline constexpr bool has_function_call_operator_v 
= has_function_call_operator<T>::value;

така че код като следния да доведе до правилния резултат:

#include <iostream>
#include <type_traits>

struct no_function_call_operator {
};

struct one_function_call_operator {
    constexpr void operator()(int) noexcept;
};

struct overloaded_function_call_operator {
    constexpr void operator()(int) noexcept;
    constexpr void operator()(double) noexcept;
    constexpr void operator()(int, double) noexcept;
};

struct templated_function_call_operator {
    template <class... Args>
    constexpr void operator()(Args&&...) noexcept;
};

struct mixed_function_call_operator
: overloaded_function_call_operator
, templated_function_call_operator {
};

template <class T>
struct has_function_call_operator: std::false_type {};

template <class T>
requires std::is_member_function_pointer_v<decltype(&T::operator())>
struct has_function_call_operator<T>: std::true_type {};

template <class T>
inline constexpr bool has_function_call_operator_v 
= has_function_call_operator<T>::value;

int main(int argc, char* argv[]) {
    std::cout << has_function_call_operator_v<no_function_call_operator>;
    std::cout << has_function_call_operator_v<one_function_call_operator>;
    std::cout << has_function_call_operator_v<overloaded_function_call_operator>;
    std::cout << has_function_call_operator_v<templated_function_call_operator>;
    std::cout << has_function_call_operator_v<mixed_function_call_operator>;
    std::cout << std::endl;
}

В момента той отпечатва 01000 вместо 01111. Ако не е възможно в най-широкия възможен смисъл, може да се приеме, че T е наследимо, ако това помага. Най-странните възможни трикове за метапрограмиране на шаблони са добре дошли, стига да са напълно съвместими със стандарта C++20.


person Vincent    schedule 15.06.2020    source източник
comment
&T::operator() е двусмислено за 3-те неуспешни случая.   -  person Jarod42    schedule 16.06.2020
comment
Защо изобщо искаш да знаеш това? Каква е ползата да знаеш, че дадена функция съществува, ако не знаеш как да я извикаш?   -  person Nicol Bolas    schedule 16.06.2020
comment
Чувствам, че това е валиден дубликат.   -  person Nicol Bolas    schedule 16.06.2020


Отговори (1)


&T::operator() е двусмислено за 3-те неуспешни случая.

Така че намерените ви черти е, че има недвусмислено operator()

Тъй като позволявате T да не е final, можем да приложим вашите характеристики към (фалшив) клас със съществуващ наследен operator() и клас за тестване:

template <class T>
struct has_one_function_call_operator: std::false_type {};

template <class T>
requires std::is_member_function_pointer_v<decltype(&T::operator())>
struct has_one_function_call_operator<T>: std::true_type {};

struct WithOp
{
    void operator()() const;  
};

template <typename T>
struct Mixin : T, WithOp {};

// if T has no `operator()`, Mixin<T> has unambiguous `operator()` coming from `WithOp`
// else Mixin<T> has ambiguous `operator()`
template <class T>
using has_function_call_operator =
    std::bool_constant<!has_one_function_call_operator<Mixin<T>>::value>;

template <class T>
inline constexpr bool has_function_call_operator_v 
= has_function_call_operator<T>::value;

Демо

person Jarod42    schedule 16.06.2020