Как создать шаблонный оператор, который будет принимать переменное количество аргументов в умный указатель на объекты типа Т, которые могут быть функциями?

Как можно использовать SFINAE для выключения перегрузки функции smart_pointer, описанной в коде?
  • 15 июля 2024 г. 19:42
Ответы на вопрос 2
Для создания шаблонного оператора, который принимает переменное количество аргументов в умный указатель на объекты типа Т, которые могут быть функциями, можно воспользоваться следующим кодом:

```cpp
template <typename T, typename... Args>
auto make_smart_pointer(Args&&... args) {
    return std::make_shared<T>(std::forward<Args>(args)...);
}
```

Этот шаблонный оператор `make_smart_pointer` принимает тип `T` и переменное количество аргументов `Args`, затем использует `std::make_shared` для создания умного указателя на объект типа `T` с переданными аргументами.

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

```cpp
// Данный код использует SFINAE для выключения перегрузки функции smart_pointer

template <typename T>
struct is_callable {
private:
    template <typename U>
    static auto test(U* p) -> decltype((*p)(), void(), std::true_type{});

    template <typename U>
    static std::false_type test(...);

public:
    static constexpr bool value = std::is_same_v<decltype(test<T>(0)), std::true_type>;
};

template <typename T,
          typename = std::enable_if_t<!is_callable<T>::value>>
void smart_pointer(T obj) {
    // Реализация для случая, когда переданный объект не является функцией
}

```

В данном коде используется структура `is_callable`, которая через SFINAE проверяет, является ли тип `T` вызываемым (то есть функцией). Затем с помощью `std::enable_if` и переданного значения `is_callable<T>::value`, функция `smart_pointer` будет выключена для вызываемых типов `T`.
Вот минимальный рабочий пример. В вашей реализации return_type проблема в том, что вы этот шаблон применяете к указателю на функцию. Если там поставить * в специализации шаблона - то все компилируется и даже работает. 

template<typename T>
struct return_type;
template<typename R, typename... Args>
struct return_type<R(*)(Args...)>
{
	using type = R;
};

typedef bool (*function)(int);

template<typename T>
class smart_pointer {
public:    
    smart_pointer(T func) : func_(func) {}
    
    template<typename R = typename return_type<T>::type, typename ...Args>
    R operator()(Args... args) const {
        return func_(args...);
    }
    
    T func_;
};

bool foo(int t) {
    return t % 2 == 0;
}


int main() {
    smart_pointer<function> sm(&foo);
    std::cout << sm(5);

    return 0;
}
Похожие вопросы