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.
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
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With