How do I use std::constructible_from

Viewed 356

I am starting on C++ concepts and have trouble using them.

E.g. Here I want to make an optimistic create_unique function.

template<typename Arg, constructible_from<Arg> CreatedClass >       *1
unique_ptr<CreatedClass>
create_unique( Arg && arg ) {
    return make_unique<CreatedClass>( forward<Arg>( arg ) );
}
template<typename CreatedClass, typename Arg, 
         enable_if_t< !is_constructible<CreatedClass, Arg>::value, int > = 0>   *2
unique_ptr<CreatedClass>
create_unique( Arg && arg ) {
    throw runtime_error( "CreatedClass is not constructible from arg." );
}

int main() {
    auto x = create_unique2<string>("Hello"s);    *3
    // auto x = create_unique2<string>(42);
}

This does not compile because in *1 CreatedClass is placed after Arg. So in order for that to compile I have to explicitly specify both template arguments.

    auto x = create_unique2<string, string>("Hello"s);

If I write

template<constructible_from<string> CreatedClass, typename Arg >       *1
unique_ptr<CreatedClass>
create_unique( Arg && arg ) {
    return make_unique<CreatedClass>( forward<Arg>( arg ) );
}

then *3 compiles, but now CreatedClass is no longer dependent on Arg.

After this, how do I specify the negative case *2? It seems a bit un-clean to use the old-school enable_if.

1 Answers

Just do:

template <typename CreatedClass, typename Arg>
    requires std::constructible_from<CreatedClass, Arg>
auto create_unique(Arg&&) -> std::unique_ptr<CreatedClass>

You don't have to use the terser constraint syntax - requires is always available.

The negative case would then be an overload with no constraint:

template <typename CreatedClass, typename Arg>
auto create_unique(Arg&&) -> std::unique_ptr<CreatedClass>

The more constrained case would be preferred. But this is highly questionable, why would you want to defer this error to runtime? Seems way better to diagnose at compile type by just not having a viable overload of create_unique...

Related