Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make argument explicit?

explicit can be used on eg. a constructor or conversion function to avoid implicitly calling that constructer/conversion - in short.

Im interested in if it is possible to make a single argument explicit somehow (short of roling a new type) ? perhaps using compiler extensions ?

Using a reference makes copy-construction impossible, so that is a solution, albeit not the one im looking for. It would be neat tool/interface specifier sometimes to be able to force explicit at a function level.

void f(std::string& s); //cannot copy convert into s

void f(const std::string& t);//calling with char* allowed

Specificly for strings, what type should be used to avoid construction from char* ?

like image 332
darune Avatar asked Dec 04 '22 17:12

darune


2 Answers

You can't mark the parameter explicit, but what you can do is add an overload that has an rvalue reference parameter and delete it like

void f(const std::string& t);
void f(std::string&&) = delete;

What this will do is it will allow f to accept a std::string, but if an rvalue is created because of an implicit conversion then the rvalue reference overload will be selected instead and you'll get a compiler error about using a deleted function.

The reason this works is that an rvalue reference parameter beats a reference to const in overload resolution, so it will always be called when passing a temporary. It's only after the function is selected that the compiler see that it's deleted so it issues an error.

like image 113
NathanOliver Avatar answered Dec 24 '22 00:12

NathanOliver


With C++20, you can do:

void f(std::same_as<std::string> auto const& s);

With C++17, this is equivalent to:

template <typename T,
    std::enable_if_t<std::is_same_v<T, std::string>, int> = 0>
void f(T const& s);

That is, we have to deduce T to be exactly std::string (which string literals or other char pointers obviously are not).


Note that this rejects types like:

struct D : std::string { };

Which would not require a conversion either. If you want to allow those, that's changing the concept to std::derived_from or the enable_if to use std::is_convertible_v<T*, std::string*>.

like image 38
Barry Avatar answered Dec 23 '22 23:12

Barry