With Visual C++ 2010, I have a class like this:
class MyClass{
public:
MyClass(){}
MyClass(MyClass &){/*...*/} //A
MyClass(const MyClass &){/*...*/} //B
template<typename T> MyClass(T &&t){ static_assert(
!std::is_same<typename
std::remove_cv<typename std::remove_reference<T>::type>::type,
MyClass>::value,
"Wrapping over wrapping is not allowed!"); } //C
};
int main(int, char**){
MyClass a;
const MyClass b(a); //assert fail if line A removed
auto c=b; //assert fail if line B removed
}
//If both A and B exists
//Warning C4521: multiple copy constructors specified
//Furthermore, if both A and B removed
//No error or warnings; VC2010 accepts peacefully.
//In debug mode you will find the compiler generated trivial copy constructor
According to C++ standard, both line A and B are considered copy constructors, and C is a convert constructor. It is not surprising that I receive a warning that I declared multiple copy constructors. However, if I remove any of them, the static_assert fails and the code would not compile, that means the template constructor received control.
I am sure that this behaviour follows the rule of function overloading. However is this a conflict of two rules? If A and B are copy constructors and one of them was declared, any attempt to copy the objects should not drop to the template, is it right?
Update:
According to N3242, 12.8.7,
"a member function template is NEVER INSTANTIATED to perform the copy of a class object to an object of its class type."
the correct implementation should be:
No assert failure should occur when either A or B or both removed.
If line B is removed, construction of c should fail because b is const.
If both lines are removed, compiler should generate a copy constructor for the class.
It is up to the implementation to warn the user if both lines exists.
Any comment?
First of all, template<T> should be template <typename T>.
I am using gcc 4.4.3 on 64-bit Ubuntu Linux, the codes behave differently from what you have demonstrated in the post.
If nothing changed, the codes could be compiled without any warning. The constructor A and B are evoked one after another.
If I comment line A, it fails to be compiled just as what you said: failing in line const MyClass b(a);. The reason is that the object a is not constant, so constructor B can not be matched and the compiler has to instantiate the template constructor. Of course, const MyClass and MyClass are different types.
However, if I comment line B only, the codes could be compiled successfully and the template copy constructor was evoked. Object b is a constant object, so construct A can not be matched and the compiler instantiate the template constructor. However, the question remains: should the static_assert fails or not? The difference may be because of the platform/compiler difference. GCC seems implementing the is_same<MyClass&&, MyClass>::value to be true. You may use typeid to print out both of the types.
If A and B are copy constructors and one of them was declared, any attempt to copy the objects should not drop to the template, is it right?
A constructor that is not a copy constructor can still be used to copy objects. In your case the constructor instantiated from the constructor template is used for copying the object. Which is fine.
Related
It seems empirically that C++ always prefers a list initializer over a value initializer. My question is thus how can I force value initialization of a type that also supports a direct list initialization. Here is a minimal non-working example:
#include <initializer_list>
using namespace std;
struct foo {
foo(int) {}
foo(initializer_list<char>) {}
};
struct bar {
foo f{256};
};
In this example, I would like f to be initialized using the constructor foo(int) rather than the foo(initializer_list<char>). However, both GCC and Clang reject the code because 256 is too big for a char, which means the C++ spec requires choosing the list initializer. Obviously commenting out the second constructor of foo fixes the problem. What's the easiest way to define bar so as to use value initialization on field f? Ideally I could avoid copy initializing f, because in my real example there is no copy constructor.
update
To clarify: of course it's possible to initialize f explicitly in every single constructor of bar. But my question is specifically about the member initialization syntax because in situations with huge numbers of constructors it is preferable just to initialize certain fields in one place rather than to copy the code all over.
So long as you require foo to be non copyable/moveable, and you require foo to have an initializer_list constructor that could be used instead of a constructor, this is the behavior you get. Therefore, you have to change one of these facts if you want to solve this problem.
If you cannot change the definition of foo at all, then you're screwed. Complain to whomever owns the class.
The second fact is probably the easiest to change, but even that will not be without consequences:
struct il {};
struct foo {
foo(int) {}
foo(il, initializer_list<char>) {}
};
This completely disambiguate the problem. foo{256} will always call the single-integer constructor. However, foo technically has no initializer_list constructors; you instead must use the tag type il to call it with an initializer list of values:
foo f{il{}, {/*actual list*/}};
This requires more braced, but there is no real alternative.
Note that in C++17, guaranteed elision lets you do this:
struct bar {
foo f = foo(256);
};
Regardless of whether foo is mobile or not.
I have written two custom classes, called A and B
My B class has a member variable a, and it has a function:
void B::setA(A s)
{
a = s;
}
However, this line is giving me an error:
'operator =' function is unavailable in 'A'.
From my understanding, this means somehow the compiler is not creating a default copy assignment function for my A class. However, I don't see why... the only constructor I've written in A looks like...
class A
{
//...
public:
A() {};
//...
};
Now in truth, A and B are large classes with a lot of member variables, and the names aren't really A and B. Short of posting the entire source for both of these classes, could anyone tell me what types of things I might look for when trying to diagnose that error message? Just to be clear, I never use pointers or low-level features like that so, as far as I know, the default copy-assignment should work fine for class A.
edit:
Someone mentioned that one of the member variables of A might be to blame, so here are all of the types:
const std::string
static const bool
static std::map<int,std::string>
std::vector
std::map<int, C>
where C is a struct that I defined in the same header file that A is in. It just contains a few integers and strings.
You have in class A a non-static data member declared as
const std::string
that is with the qualifier const. In this case the implicit copy assignment operator is defined by the compiler as deleted.
const members don't mix well with copy assignment operators. Not only won't the compiler generate one for you, it would also be semantically hard to come up with an "assignment" which does not actually assign everything.
Nothing stops you from writing an assignment operator which does not assign to your const member, of course, but that would mean one of two things:
The assigned object does not appear to the client as an identical copy of the source, which is not what one would except from a copy assignment operator, so that would be a case of operator-overloading abuse.
The member variable does not have an observable effect to the outside. In that case, one must wonder why it exists in the first place, or rather why it is not mutable rather than const.
I would like to know where is this form of constructor calling is documented.
This syntax apparently works since Visual Studio version 6.0 (I know it does not compile using G++).
Please note that I am not looking for alternatives and I don't need to know that it's good or evil.
class Foo
{
public:
int m_value;
Foo() : m_value(0) {}
};
Foo o;
o.m_value = 5;
o.Foo::Foo(); // Explicit constructor call!
EXPECT_EQ(0, o.m_value); // True!
I first found this syntax reading this article:
http://www.dreamincode.net/forums/topic/160032-finite-state-machines/
This post also refers to this syntax as well:
Can I call a constructor from another constructor (do constructor chaining) in C++?
Another post discussing the matter:
Explicit constructor call in C++
The supposed explicit constructor call is not valid C++ syntax. The fact that MSVC accepts such code is a bug.
Its of no use since you are creating a transient object in between and it dies when the scope ends.What ever value contain in object o remains the same, so u got the True value
I'm seeing some different behavior between g++ and msvc around value initializing non-copyable objects. Consider a class that is non-copyable:
class noncopyable_base
{
public:
noncopyable_base() {}
private:
noncopyable_base(const noncopyable_base &);
noncopyable_base &operator=(const noncopyable_base &);
};
class noncopyable : private noncopyable_base
{
public:
noncopyable() : x_(0) {}
noncopyable(int x) : x_(x) {}
private:
int x_;
};
and a template that uses value initialization so that the value will get a known value even when the type is POD:
template <class T>
void doit()
{
T t = T();
...
}
and trying to use those together:
doit<noncopyable>();
This works fine on msvc as of VC++ 9.0 but fails on every version of g++ I tested this with (including version 4.5.0) because the copy constructor is private.
Two questions:
Which behavior is standards compliant?
Any suggestion of how to work around this in gcc (and to be clear, changing that to T t; is not an acceptable solution as this breaks POD types).
P.S. I see the same problem with boost::noncopyable.
The behavior you're seeing in MSVC is an extension, though it's documented as such in a roundabout way on the following page (emphasis mine) http://msdn.microsoft.com/en-us/library/0yw5843c.aspx:
The equal-sign initialization syntax is different from the function-style syntax, even though the generated code is identical in most cases. The difference is that when the equal-sign syntax is used, the compiler has to behave as if the following sequence of events were taking place:
Creating a temporary object of the same type as the object being initialized.
Copying the temporary object to the object.
The constructor must be accessible before the compiler can perform these steps. Even though the compiler can eliminate the temporary creation and copy steps in most cases, an inaccessible copy constructor causes equal-sign initialization to fail (under /Za, /Ze (Disable Language Extensions)).
See Ben Voigt's answer for a workaround which is a simplified version of boost::value_initialized, as pointed out by litb in a comment to Ben's answer. The docs for boost::value_initalized has a great discussion of the problem, the workaround, and some of the pitfalls of various compiler issues.
I don't think template metaprogamming is needed. Try
template <class T>
void doit()
{
struct initer { T t; initer() : t() {} } inited;
T& t = inited.t;
...
}
There's §12.8/14:
A program is ill-formed if the copy constructor or the copy assignment operator for an object is implicitly used and the special member function is not accessible.
And then there's §12.8/15:
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects.
So, the question is really, if the implementation omits the call to the copy constructor (which it is clearly allowed to do), is the copy constructor actually used?
And, the answer to that is yes, per §3.2/2:
A copy constructor is used even if the call is actually elided by the implementation.
Have you seen what happens when you compile using /Wall with MSVC? It states the following about your class:
nocopy.cc(21) : warning C4625: 'noncopyable' : copy constructor could not be
generated because a base class copy constructor is inaccessible
nocopy.cc(21) : warning C4626: 'noncopyable' : assignment operator could not be
generated because a base class assignment operator is inaccessible
GCC remedy:
create a copy constructor for noncopyable (and an assignment operator ideally!) that does what it can to copy the information from noncopyable_base, namely invoking the constructor for noncopyable_base that has no parameters (since that is the only one accessible by noncopyable) and then copying any data from noncopyable_base. Given the definition of noncopyable_base, however, it seems there is no data to copy, so the simple addition of noncopyable_base() to the initializer list of a new noncopyable(const noncopyable &) function should work.
Take note of what MSVC said about your program though. Also note that if you use T t() rather than T t = T(), another warning (C4930) is generated by MSVC, though GCC happily accepts it either way without any warning issued.
I just try to understand the behaviour of the following situation:
template <typename T1>
struct A{
template <typename T2>
A(T2 val){
cout<<"sizeof(T1): "<<sizeof(T1)<<" sizeof(T2): "<<sizeof(T2)<<endl;
}
T1 dummyField;
};
so - the class is templated with T1 and the constructor is templated with T2
now - if i write:
A<bool> a = A<bool>(true);
the output is as expected:
sizeof(T1): 1 sizeof(T2): 1
however - if i write:
A<bool> a = A<float>(3.5f);
the output is:
sizeof(T1): 4 sizeof(T2): 4
sizeof(T1): 1 sizeof(T2): 4
why is the constructor called twice with template parameter float?
thanks for satisfying my curiosity
How to avoid copying?
In both cases two constructors are called, however you do not see it in the first case as one of them is the compiler generated one. If you want to avoid copying, you need to use a different syntax, like this:
A<bool> a(true);
A<bool> a(3.5f);
Why (and what) copy constructor is called?
A<bool> a = A<bool>(true);
Here the A (bool val) constructor is used to construct the temporary value, while default compiler generated copy constructor is used to perform the copy of A to A. You are copying the same type, and for same type copy constructor is used. The interesting and not obvious fact here is: Template constructor is never used as a copy constructor, even if it looks like one.
A<bool> a = A<float>(3.5f);
Here A<float>(float val) constructor is used first to construct the temporary value, and then A<bool>( A<float> val) templated constructor is used to perform the copy.
in your first example you make a implicit call to the copy constructor
A<bool>(A<bool> const&)
in your second example this wont work as you have two different types
so the compiler has to use your templated constructor to create a new object
declaring
template <typename T2>
A(A<T2>const& val){
cout<<sizeof(val.dummmyField)<<endl;
}
should make this clear
Because you first create a float-instance of the template class.
This is the A<float>(3.5f)-Part.
Then create the A<bool> by covert the A<float> to a A<bool>. So the constructor is first called for the A<float>-instance. The the copy-constructor of A<bool> is called.