How to safely allow single argument templated constructor without using explicit? - c++

I have a Value class which I use for wrapping and converting basic types.
class Value {
public:
template <typename T>
Value(const T &value) : value_(StringMaker<T>(value)) {} // Not marked explicit
// Example -> Convert to String
std::string AsString() const;
// Example -> Convert to Int
int AsInt(bool *err_flag = nullptr);
private:
const std::string value_;
// Helper method to convert values to a string
template <typename T>
std::string StringMaker(const T &value);
};
I have other classes which use the Value class e.g. the class Foo:
struct Foo {
explicit Foo(const Value &value) : bar(value) {}
const Value bar;
};
With usage as follows:
// Normal use
std::cout << "Value converted to \"std::string\": " << Value(100).AsString()
<< std::endl;
// Normal use via Foo class
std::cout << "Value converted to \"std::string\" via \"Foo\": "
<< Foo(100).bar.AsString() << std::endl;
and output:
Value converted to "std::string": 100
Value converted to "std::string" via "Foo": 100
I would like to make use of a implicit constructor for Value, but with cpplint and Cppcheck I get the warning:
Single-parameter constructors should be marked explicit. [runtime/explicit] [5]
If I add explicit to the Value constructor I get additional errors like:
error: no matching function for call to ‘Foo::Foo(int)’
<< Foo(100).bar.AsString() << std::endl;
Thus, is there a safe way to keep the static analysis tools happy and also use implicit conversion?
Here is a working example with additional use-cases.

Thus, is there a safe way to keep the static analysis tools happy [...]
Yes, make the converting constructor explicit ;)
You can only disable or ignore the warning or make the constructor explicit. Though the warning exists for a reason, implicit conversions can be a source of confusion. Because Values constructor is a template, you can pass any parameter to Foos constructor too. Latest when you want to add a second constructor for Foo this can be confusing, for example:
struct Foo {
explicit Foo(const Value &value) : bar(value) { /* do something */}
explicit Foo(int x): bar(x) { /* do something else */}
const Value bar;
};
Then Foo(100) suddenly calls a different constructor, which instead of something does something else. Hence I suggest to make contructor of Value explicit.
Thus, I cannot do explicit with only Foo(100)
explicit means just that: You have to explicitly call the constructor. Foo(100) does not explicitly call Values constructor, but Foo(Value(100)) does. The sequence of conversions is exactly the same, but the code is more clear.
So instead of:
std::cout << Foo(100).bar.AsString() << std::endl;
write
std::cout << Foo(Value(100)).bar.AsString() << std::endl;
Alternatively, find a way to silence the warning. In rare cases implicit conversions are just right, but you need to be aware of the implications.

Related

C++ template: no matching function for call

I cannot understand why this program fails to compile both with g++ 7.3 or clang++ 5.0 using -std=c++14.
A can be initialized from a const int as shown. A const reference to A can also be create from a const int but call to f(const A &) with a const int fails. Why?
#include <iostream>
struct V {
int i;
template <class T>
V(const T &t) : i{t} {}
};
struct A {
int i;
A(V v) : i{v.i} {}
};
void f(const A &) {}
int main() {
const auto i = 42;
const A a1{i}; // OK
std::cout << a1.i << '\n'; // 42
const A &a2 = A{i}; // OK
std::cout << a2.i << '\n'; // 42
f(i); // no matching function for call to 'f'
return 0;
}
Given f(i);, copy initialization is applied. And i (with type const int) needs to be converted to A, two user-defined conversions are required; from const int to V, and from V to A. But only one user-defined conversion is allowed in one implicit conversion sequence.
Bot const A a1{i}; and const A &a2 = A{i}; are direct initialization, only one implicit conversion from i (with type const int) to the argument of A's constructor (i.e. V) is required, so they work fine.
Note the difference between copy initialization and direct initialization,
In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.
As a workaround, you can perform explicit conversion on i before passing it to f().
Converting i to an A for the purpose of the function call will require two user defined conversions (int -> V -> A). The standard places a hard limit of a single user defined conversion on each implicit conversion sequence.
The same would happen if you were to try and bind a2 to i "directly". So you need to do a functional style cast (A{i}) when giving an argument to f as well.
You need two consecutive implicit type conversion here however C++ can do single conversion implicitley for you. If you want to let the compiler to generate the correct typed code for you, use template for the function f like following.
template <typename T>
void f(const T & x) { std::cout << x << std::endl;}
The reason why you need two type conversion is because of having only one constructor which takes type V in the struct. If you want to get rid of two type conversion as a second solution, you can add another constructor which takes int as a parameter like following
struct A {
int i;
A(V v) : i{v.i} {}
A(int theI) : i{theI} { }
};
Two user defined conversions are not supported in copy initialization. Simple work around to the problem is to wrap i with A while passing to funtion f with f(A(i))

Assignment vs constructor in C++ [duplicate]

I wrote some code S s; ... s = {};, expecting it to end up the same as S s = {};. However it didn't. The following example reproduces the problem:
#include <iostream>
struct S
{
S(): a(5) { }
S(int t): a(t) {}
S &operator=(int t) { a = t; return *this; }
S &operator=(S const &t) = default;
int a;
};
int main()
{
S s = {};
S t;
t = {};
std::cout << s.a << '\n';
std::cout << t.a << '\n';
}
The output is:
5
0
My questions are:
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
Is there a tidy workaround, without changing S?
My intent is s = S{}; . Writing s = {}; would be convenient if it worked. I'm currently using s = decltype(s){}; however I'd prefer to avoid repeating the type or the variable name.
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
{} to int is the identity conversion ([over.ics.list]/9). {} to S is a user-defined conversion ([over.ics.list]/6) (technically, it's {} to const S&, and goes through [over.ics.list]/8 and [over.ics.ref] first before coming back to [over.ics.list]/6).
The first wins.
Is there a tidy workaround?
A variation of the trick std::experimental::optional pulls to make t = {} always make t empty.
The key is to make operator=(int) a template. If you want to accept int and only int, then it becomes
template<class Int, std::enable_if_t<std::is_same<Int, int>{}, int> = 0>
S& operator=(Int t) { a = t; return *this; }
Different constraints can be used if you want to enable conversions (you'd probably also want to take the argument by reference in that case).
The point is that by making the right operand's type a template parameter, you block t = {} from using this overload - because {} is a non-deduced context.
...without changing S?
Does template<class T> T default_constructed_instance_of(const T&) { return {}; } and then s = default_constructed_instance_of(s);count?
First of all, the case has nothing to do with the "int" version of the assignment operator, you can just delete it. You can actually delete the other assignment operator too as it will be generated by the compiler. IE this kind of type automatically receives copy/move constructors and the assignment operator. (ie they are not prohibited and you are just repeating what the compiler does automatically with explicit notation)
The first case
uses copy initialization:
S s = {}; // the default constructor is invoked
That is a post-construction copy assignment, yet compilers optimize such simple cases. You should use direction initialization instead:
S s{}; // the default constructor is invoked (as you have it)
Note, you can also write:
S s; // the default constructor is invoked if you have it
The second case
What you should write is direct initialization of the right hand side of the copy assignment:
t = S{};
This notation will invoke the default constructor (if there is one), or value initialization for the members (as long as the type is an aggregate). Here is the relevant info: http://en.cppreference.com/w/cpp/language/value_initialization

In C++, how to make it such that the constructor can have different types of arguments?

I want to define a constructor for a class CLS. And I want to include different situations in my definition of the constructor. For example, I want the constructor to work when the argument is void:
CLS::CLS();
or when the argument is an integer,
CLS::CLS(int a);
How do I do this?
Your question actually is too generic, in my opinion.
A general answer is function overloading.
In short you can simply write two different function (method in that case) with the same name, but different argument. You can specify a different body for each of them. For example:
class CLS {
public:
CLS(int n) {
// do something
}
CLS(char c) {
// do something else
}
};
Then you can simply construct an object:
// ... somewhere
CLS object1(12); // 12 is a int, then the first 'ctor will be invoked
CLS object2('b'); // 'b' is a char, the second 'ctor will be invoked, instead.
A "move advance" answer requires the usage of template.
In short you can write a single constructor which accept a generic type as argument and specify a behaviour in case that type follow certain traits.
class CLS {
public:
template<typename T>
CLS(T t) {
if (std::is_arithmetic<T>::value) {
// do something if the type is an arithmetic
} else {
// do something else
}
}
};
That approach could be useful when you can "generalize" (for almost all the body) the behaviour of your constructor, and you want to aggregate different type.
Another approach is to take advantage of Default Arguments. For example
#include <iostream>
class example
{
public:
int val;
example(int in = 0): val(in)
{
}
};
int main()
{
example a(10);
example b;
std::cout << a.val << "," << b.val << std::endl;
}
will output
10,0

i am trying to compile below code with dummy class [duplicate]

Consider this simple example:
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
Some random situations where conversion functions are used and not used follow.
First, note that conversion functions are never used to convert to the same class type or to a base class type.
Conversion during argument passing
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
B b = A(); // called!
Conversion to reference
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
Conversion to function pointers
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
This thing can actually become quite useful sometimes.
Conversion to non class types
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t needs be different from int then).
Conversion function template
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
Conversions aren't magic. Just because A has a conversion to B and B has a foo method doesn't mean that a.foo() will call B::foo().
The compiler tries to use a conversion in four situations
You explicitly cast a variable to another type
You pass the variable as an argument to a function that expects a different type in that position (operators count as functions here)
You assign the variable to a variable of a different type
You use the variable copy-construct or initialize a variable of a different type
There are three types of conversions, other than those involved with inheritance
Built-in conversions (e.g. int-to-double)
Implicit construction, where class B defines a constructor taking a single argument of type A, and does not mark it with the "explicit" keyword
User-defined conversion operators, where class A defines an operator B (as in your example)
How the compiler decides which type of conversion to use and when (especially when there are multiple choices) is pretty involved, and I'd do a bad job of trying to condense it into an answer on SO. Section 12.3 of the C++ standard discusses implicit construction and user-defined conversion operators.
(There may be some conversion situations or methods that I haven't thought of, so please comment or edit them if you see something missing)
Implicit conversion (whether by conversion operators or non-explicit constructors) occurs when passing parameters to functions (including overloaded and default operators for classes). In addition to this, there are some implicit conversions performed on arithmetic types (so adding a char and a long results in the addition of two longs, with a long result).
Implicit conversion does not apply to the object on which a member function call is made: for the purposes of implicit conversion, "this" is not a function parameter.
The compiler will attempt one(!) user-defined cast (implicit ctor or cast operator) if you try to use an object (reference) of type T where U is required.
The . operator, however, will always try to access a member of the object (reference) on its left side. That's just the way it's defined. If you want something more fancy, that's what operator->() can be overloaded for.
You should do
((person)p).think();
The compiler doesn't have the information for automatically casting to person, so you need explicit casting.
If you would use something like
person pers = p;
Then the compiler has information for implicit casting to person.
You can have "casting" through constructors:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
These are some brief examples. Casting (implicit, explicit, etc) needs more to explain. You can find details in serious C++ books (see the questions about C++ books on stack overflow for good titles, like this one).
//Virtual table Fuction(VFT)
#include <iostream>
using namespace std;
class smartref {
public:
virtual char think() { }//for Late bindig make virtual function if not make virtual function of char think() {} then become early binding and pointer call this class function
smartref() : data(new char) { }
operator char(){ return *data; }
private:
char* data;
};
class person:public smartref
{
public:
char think() { std::cout << "I am thinking"; }
};
int main() {
smartref *p;//make pointer of class
person o1;//make object of class
p=&o1;//store object address in pointer
p->think(); // Late Binding in class person
return 0;
}

Why is the 'explicit' keyword allowing implicit conversions?

class Test {
private:
int value;
public:
void display(void)
{
cout << "Value [" << value << "]" << endl;
}
explicit Test(int i)
{
value=i;
}
};
int main() {
Test a(5);
Test b(4.9);
a.display();
b.display();
cin.get();
return 0;
}
Float value gets converted to int even though explicit is mentioned.
I was expecting (incorrectly) that float does not get converted to integer and object b not to be constructed.
explicit refers to the constructor itself, not the constructor's parameters. Your explicit constructor may not be used as an implicit conversion to type Test.
void function( Test param );
function( 5 ); // Your "explicit" makes this call an error.
// The parameter must be explicitly cast, such as Test(5)
In C++11 or later, you can prevent implicit parameter conversions using the = delete syntax on a template parameter.
Test(int i)
{
value=i;
}
template<typename T>
Test(const T&) = delete;
// ^ Aside from your int constructor and the implicitly-generated
// copy and move constructors, this will be a better match for any other type
In C++20 or later, you can prevent implicit parameter conversions using the std::same_as concept.
Test(std::same_as<int> auto i)
{
value=i;
}
explicit just prevents any implicit conversions. So if you had:
void foo(Test t);
You cannot call foo(4); because the Test constructor is explicit. You'd have to call foo(Test(4));. The explicit keyword has nothing to do with any conversions that might have to happen during construction.
From the standard [class.conv.ctor]:
An explicit constructor constructs objects just like non-explicit constructors, but does so only where the
direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used.
Which means that Test t = 4; is also illegal, but Test t(42.0) is fine.
It's a Floating–integral conversion.
That is: it's an implicit conversion between a prvalue of type double to a prvalue of type signed int. It discards the fractional part.
TL;DR: the conversion happens between 'double' and 'int', not in your Test constructor. If you want to prevent that constructor to be called with a float or a double you can add the definition:
Test(double) = delete;
In your Test class. Live on compiler explorer