I recently came across a class like the following
class Foo {
public:
Foo(std::string msg) {}
private:
Foo(bool b) {}
};
I noticed that trying to create an object of this class by means of
Foo foo("blah");
causes a compilation error telling that Foo::Foo(bool) is private. Apparently, if the argument is not an actual std::string, the compiler prefers to use the constructor with the bool argument. On the other hand, if the private constructor is not given, above code compiles just fine.
Why is it that the "bool-constructor" has precedence over the "string-constructor" althogh the type of the passed argument does not fit to any of them? Is this just a matter of definition or does it have a deeper meaning and some good reason?
The reason has to do with conversion operator precedence. Each of the calls includes an implicit conversion
pointer -> std::string
pointer -> bool
In this case #1 is a user defined conversion and #2 is a language / compiler defined one. User defined conversions have a much lower precedence and hence the other conversion is preferred.
Edit
Here is a similar question which has a much more in depth explanation of the precedence checks involved
conversion precedence in c++
Related
Recently, I've decided to write a class storing a variant with reference_wrapper<const vector> and vector for having a choice either to own the value or having only a reference of it. That is, std::variant<vector<string>, reference_wrapper<const vector<string>>>.
The interesting part is what the variant stores depending on initialization.
I did a small investigation, and it turned out, that in all cases vector<string> type wins, except for the case when passing via std::cref. The same applies to functions (somewhat expected, because constructors are similar to functions in this way)
void f(vector<string>); // #1
void f(reference_wrapper<const vector<string>>); // #2
vector<string> data;
const vector<string>& get_data();
f(data); // #1
f(std::cref(data)) // #2
f(get_data()); // #1
f(std::cref(get_data())) // #2
The question is why the vector<string> has the priority here. I looked at Best viable function section here , but it didn't make much sense. It seems, that
4) or, if not that, F1 is a non-template function while F2 is a template specialization
part chooses vector<string> over reference_wrapper<vector<string>> (because reference_wrapper constructor is templated), but I'm not sure, because I can't fully understand if they are equal using the rule
1) There is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
Can someone please describe all the implicit conversions applied in each case and show the true reason why one overload is preferred over another? To me, they are as follows:
f(data) = f(vector<string>&) -> (*exact match* implicit conversion) -> f(vector<string>)
f(data) = f(vector<string>&) -> (*conversion* implicit conversion) -> f(reference_wrapper<vector<string>>)
Did I miss something?
Another question, connected to this topic: Ranking of implicit conversion sequences section again,here leaves a question, is T(const T&) considered an Exact match (user-defined conversion of class type to the same class) or Conversion?
First, Although std::reference_wrapper is part of standard library it is treated as user-defined type.
For example an implicit conversion from std::vector & to const std::vector & is always preferred over an implicit conversion from std::vector& to std::reference_wrapper<vector>. That is because (as per standard) the former one is a standard conversion, but the later is a user-defined conversion. the first one is called standard conversion because it adds a const to your type but the second is treated as converting some type to totally different type.
check this code and see cppreference.com.
Second, I'm trying to guess some good alternative. I see you want either to store a reference to vector OR move/(copy as cheap as possible) or (you could say directly initialize) the data inside your class if it is not already stored (safely) in some variable. Maybe you could consider using move semantics. you can play with code here
using TVar = std::variant<reference_wrapper<const vector<string>>, vector<string>>;
class Config {
private:
TVar data;
public:
const vector<string>& get_data() const{
if (data.index() == 1)
return get<1>(data);
else return get<0>(data);
}
Config(const vector<string>& it):data(cref(it)){}
Config(vector<string>&& it):data(move(it)){}
};
Here we have two functions.
One that takes reference to "stored value" (more precisely lvalue). wrapping it in cref so that it causes the reference_wrapper alternative in the variant to be the best overload.
The other does the magic. it is the reference to values that are either written directly (aka pvalues) and values that use the magic std::move function (aka xvalues). if you have never seen this, please reference this respectable Q&A What is move semantics?
catch(...) :), this is it. also notice, you don't need the std::monostate as this is only needed for making the variant default constructible (with no arguments). you can make your class default constructible like this.
Config(vector<string>&& it = {}):data(move(it)){}
There is absolutely no reason to store reference_wrapper whatsoever. Just use a pointer like any sane programmer. reference_wrapper is used to properly trigger std::invoke and associated classes/functions like thread and bind.
I'm working on a project with is part C written and partly C++ written.
I got 2 Enums which basically represent the same, however one is wrapped inside a class and the other one is located at a global namespace due to C compatibility.
//C Code File
typedef enum
{
C_Enum_first = 0,
C_Enum_Second,
} C_Enum_T
//(obviously) C++ Code file
class CMyClass
{
public:
enum class CPP_Enum
{
first= 0,
second,
};
CPP_Enum& operator= ( const C_Enum_T& rhs);
}
Now I have a function at a global namespace scope with takes the Cpp Enum as an argument
bool FooFunc(const CMyClass::CPP_Enum value);
However due to compatibility issues with C code there are some places where this function will be called with a C Enum value
bool res = FooFunc(C_Enum_Second);
This gives me a no known conversion error.
Yes I know i can overload, but for demonstration purposes i only showed 1 enum argument. In reality there are 3 enums with will increase my needed overloads.
Why is my assignment operator not called? Do assignment operator not work implicitly on function arguments?
thx for your help
greets Julian :)
Do assignment operator not work implicitly on function arguments?
Your operator= is a member of CMyClass. It can be called like this:
CMyClass cmc;
C_Enum_t a;
CPP_Enum& x = (cmc = a);
But it will not be considered for implicit conversion from CMyClass to CPP_Enum. Consider to use a free function for the conversion instead. Also it is rather fishy that your operator= returns a reference. You didn't include the implementation, but returning a reference does not look right. What should it refer to?
This is an overloaded operator contained in a class:
inline operator const FOO() const { return _obj_of_type_FOO; }
I cannot for the life of me understand:
How I would invoke this operator?
What would be its return value?
[Secondary] Whether making it inline affects anything apart from efficiency?
That expression looks like a declaration of a conversion operator if Foo is a type and it is inside a class. The second const (the one closer to the opening curly bracket) means that the conversion can be called on const instances. Let us say the class is C. You can think of a conversion operator as a constructor outside a class. For example, you can't add constructors to the class std::string, but you can add a conversion operator to std::string to your classes. The result is that you can construct std::string from your class instance.
1) How to invoke the conversion operator: by constructing a value of type Foo from a C, for example:
Foo foo = c (where c is an instance of C, the class that declares the conversion operator). Mind you that the invocation of the conversion can happen implicitly. If you have, for example, void funOnFoo(Foo v); and an instace c of C, this might implicitly call operator const Foo: funOnFoo(c). Whether this actually does, depends on the usual things: Whether there are other overloads of funOnFoo, other conversions for C, etc.
2) The return value is const Foo
3) inline means the same thing as for any function, in particular, does not affect overload resolution
I've been playing with C++ recently, and I just stumbled upon an interesting precedence issue. I have one class with two operators: "cast to double" and "+". Like so:
class Weight {
double value_;
public:
explicit Weight(double value) : value_(value) {}
operator double() const { return value_; }
Weight operator+(const Weight& other) { return Weight(value_ + other.value_); }
};
When I try to add two instances of this class...
class Weighted {
Weight weight_;
public:
Weighted(const Weight& weight) : weight_(weight) {}
virtual Weighted twice() const {
Weight w = weight_ + weight_;
return Weighted(w);
}
};
...something unexpected happens: the compiler sees the "+" sign and casts the two weight_s to double. It then spits out a compilation error, because it can't implicitly cast the resulting double back to a Weight object, due to my explicit one-argument constructor.
The question: how can I tell the compiler to use my own Weight::operator+ to add the two objects, and to ignore the cast operator for this expression? Preferably without calling weight_.operator+(weight_), which defeats the purpose.
Update: Many thanks to chris for pointing out that the compiler is right not to use my class's operator+ because that operator is not const and the objects that are being +ed are const.
I now know of three ways to fix the above in VS2012. Do see the accepted answer from chris for additional information.
Add the explicit qualifier to Weight::operator double(). This
doesn't work in VS 2012 (no support), but it stands to reason that
it's a good solution for compilers that do accept this approach (from the accepted answer).
Remove the virtual qualifier from method Weighted::twice, but don't ask me why this works in VS.
Add the const qualifier to method Weight::operator+ (from the accepted answer).
Current version:
First of all, the virtual should have nothing to do with it. I'll bet that's a problem with MSVC, especially considering there's no difference on Clang. Anyway, your twice function is marked const. This means that members will be const Weight instead of Weight. This is a problem for operator+ because it only accepts a non-const this. Therefore, the only way the compiler can go is to convert them to double and add those.
Another problem is that adding explicit causes it to compile. In fact, this should remove the compiler's last resort of converting to double. This is indeed what happens on Clang:
error: invalid operands to binary expression ('const Weight' and 'const Weight')
Weight w = weight_ + weight_;
note: candidate function not viable: 'this' argument has type 'const Weight', but method is not marked const
Finally, making operator+ const (or a free function) is the correct solution. When you do this, you might think you'll add back this route and thus have another error from ambiguity between this and the double route, but Weight to const Weight & is a standard conversion, whereas Weight to double is a user-defined conversion, so the standard one is used and everything works.
As of the updated code in the question, this is fine. The reason it won't compile is the fault of MSVC. For reference, it does compile on Clang. It also compiles on MSVC12 and the 2013 CTP.
You may be storing the result in a Foo, but there is still an implicit conversion from double to Foo needed. You should return Foo(value_ + other.value_) in your addition operator so that the conversion is explicit. I recommend making the operator a free function as well because free operators are (almost) always at least as good as members. While I'm at it, a constructor initializer list would be a welcome change, too.
In addition, from C++11 onward, a generally preferred choice is to make your conversion operator explicit:
explicit operator double() const {return value_;}
Also note the const added in because no state is being changed.
How does constructor conversion work?
#include <iostream>
using namespace::std;
class One {
public:
One() { cout<<"One"<<endl;}
};
class Two {
public:
Two(const One&) {cout<<"Two(const One&)"<<endl;}
};
void f(Two) {cout<<"f(Two)"<<endl;}
int main() {
One one;
f(one);
}
produces the output
One
Two(const One&)
f(Two)
Any constructor that can be called with a single argument is considered an implicit conversion constructor. This includes simple 1-argument cases, and usage of default arguments.
This conversion is considered in any context that wants X and provided Y, and Y has such implicit conversion possibility. Note that a plenty of other, built-in conversions also play as a mix (like adjusting const-ness, integral and fp promotions, conversions, etc.) The rule is that at most one "user defined" implicit conversion is allowed in the mix.
In some cases it may be quite surprising, so the general advice is to make any such ctors explicit. That keyword makes the conversion possible but not implicitly: you must use T() syntax to force it.
As an example consider std::vector that has a ctor taking size_t, setting the initial size. It is explicit -- otherwise your foo(vector<double> const& ) function could be mistakenly called with foo(42).
It's right result. Since constructor is not explicit - implicit conversion works (here One is implicitly converted to Two).
one is created, then when passed to f converted to Two.
What the Two(const One&) {cout<<"Two(const One&)"<<endl;} constructor means is that you're allowed to construct a Two value at any time - implicitly - from a One. When you call f(one) it wants a Two parameter, it's given a One, so the compiler puts 2 and 2 together and says "I'll make a temporary Two from the One and complete the call to f()"... everyone will be happy. Hurray!
Compiler has to create copy of Two instance on stack. When you call f() with argument which is object of class One (or any other) compiler looks to definition of class Two and tries to find constructor which takes One(or any other) object(or reference) as an argument. When such constructor has been found it constructs object using it. It's called implicit because compiler do it without your interference.
class Foo {
public:
Foo(int number) {cout<<"Foo(int number)"<<endl;}
};
void f(Foo) {cout<<"f(Foo)"<<endl;}
int main() {
f(24);
} ///:~
Output will be:
Foo(int number)
f(Foo)