Domanda

I am wanting to write a version of make_unique that will construct the type with { ... } if that compiles, or else (...).

I have an attempt

template<typename T, typename... Args>
auto make_unique(Args&&... args) -> decltype(new T {std::forward<Args>(args)...}, std::unique_ptr<T>{}) {
    return std::unique_ptr<T>(new T { std::forward<Args>(args)... });
}

This is ready for SFINAE because it will have a substitution failure if the new T { ... } syntax doesn't work, but I don't know how to make it fail to substitute if the new T(...) syntax works, and also I don't know how to make the other one so that it fails to substitute when the new T { ... } syntax does work and compile successfully when it doesn't so it can use the new T(...) syntax.

È stato utile?

Soluzione

You could select an overload by ranking of conversions, using a dispatching technique:

#include <memory>
#include <iostream>

template<typename T, typename... Args>
auto make_unique_impl(int, Args&&... args)
-> decltype(new T {std::forward<Args>(args)...}, std::unique_ptr<T>{}) {
    std::cout << "{..} variant" << std::endl;
    return std::unique_ptr<T>(new T { std::forward<Args>(args)... });
}

template<typename T, typename... Args>
auto make_unique_impl(short, Args&&... args)
-> decltype(new T (std::forward<Args>(args)...), std::unique_ptr<T>{}) {
    std::cout << "(..) variant" << std::endl;
    return std::unique_ptr<T>(new T ( std::forward<Args>(args)... ));
}

// dispatcher
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return make_unique_impl<T>(0, std::forward<Args>(args)...);
}

The call in the dispatcher will prefer the int overload, since 0 is of type int. But if substitution fails, the other overload is also viable (via an integral conversion).

Usage example:

struct my_type
{
    my_type(int, int) {}
    my_type(std::initializer_list<int>) = delete;
};

struct my_other_type
{
    my_other_type(int, int) {}
};

int main()
{
    make_unique<my_type>(1, 2);
    make_unique<my_other_type>(1, 2);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top