I'm using MSVC10.
I have a class C which is nested in class B, which in turn is nested in class A. B has a member variable of type C, and A has a vector of Bs. Like so:
class A
{
class B
{
string foo_;
class C
{
string bar_;
} c_;
};
vector<B> b_;
};
Within A I have a member function which uses for_each with a lambda, to iterate over the vector<B>.
In that lambda I try to get a reference to the B and the C (separately):
void A::Run()
{
for_each(b_.begin(), b_.end(), [](std::vector<B>::value_type& that)
{
const B& b = that;
cout << b.foo_;
const B::C& c = b.c_; // 'B' : is not a class or namespace name
// const A::B::C& c = b.c_; <-- THIS COMPILES
cout << c.bar_;
});
}
The code: const B::C& c = b.c_; results in a compiler error, "'B' : is not a class or namespace name" even though the compiler had no problem accepting const B& b = that;
Is this syntax allowed by the language?
If I change it to: const A::B::C& c = b.c_; the compiler accepts it.
Here is a complete example for you to play with:
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void foo() {}
class A
{
public:
void Run();
struct B
{
std::string foo_;
struct C
{
std::string bar_;
} c_;
};
std::vector<B> b_;
};
void A::Run()
{
for_each(b_.begin(), b_.end(), [](std::vector<B>::value_type& that)
{
const B& b = that;
cout << b.foo_;
const B::C& c = b.c_; // 'B' : is not a class or namespace name
// const A::B::C& c = b.c_; <-- THIS COMPILES
cout << c.bar_;
});
}
int main()
{
A a;
a.Run();
}
It's a bug in the compiler. The code compiles fine with MSVC 2012 RC. I believe the pertinent bug is this one.
And the pertinent part of the standard is [expr.prim.lambda] 5.1.2 clause 7:
The lambda-expression’s compound-statement yields the function-body
(8.4) of the function call operator, but for purposes of name lookup
(3.4), determining the type and value of this (9.3.2) and transforming
id-expressions referring to non-static class members into class member
access expressions using (*this) (9.3.1), the compound-statement is
considered in the context of the lambda-expression.
Related
#include <iostream>
using namespace std;
class T1
{
const int t = 100;
public:
T1()
{
cout << "T1 constructor: " << t << endl;
}
};
When I am trying to initialize the const member variable t with 100. But it's giving me the following error:
test.cpp:21: error: ISO C++ forbids initialization of member ‘t’
test.cpp:21: error: making ‘t’ static
How can I initialize a const value?
The const variable specifies whether a variable is modifiable or not. The constant value assigned will be used each time the variable is referenced. The value assigned cannot be modified during program execution.
Bjarne Stroustrup's explanation sums it up briefly:
A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.
A const variable has to be declared within the class, but it cannot be defined in it. We need to define the const variable outside the class.
T1() : t( 100 ){}
Here the assignment t = 100 happens in initializer list, much before the class initilization occurs.
Well, you could make it static:
static const int t = 100;
or you could use a member initializer:
T1() : t(100)
{
// Other constructor stuff here
}
There are couple of ways to initialize the const members inside the class..
Definition of const member in general, needs initialization of the variable too..
1) Inside the class , if you want to initialize the const the syntax is like this
static const int a = 10; //at declaration
2) Second way can be
class A
{
static const int a; //declaration
};
const int A::a = 10; //defining the static member outside the class
3) Well if you don't want to initialize at declaration, then the other way is to through constructor, the variable needs to be initialized in the initialization list(not in the body of the constructor). It has to be like this
class A
{
const int b;
A(int c) : b(c) {} //const member initialized in initialization list
};
If you don't want to make the const data member in class static, You can initialize the const data member using the constructor of the class.
For example:
class Example{
const int x;
public:
Example(int n);
};
Example::Example(int n):x(n){
}
if there are multiple const data members in class you can use the following syntax to initialize the members:
Example::Example(int n, int z):x(n),someOtherConstVariable(z){}
You can upgrade your compiler to support C++11 and your code would work perfectly.
Use initialization list in constructor.
T1() : t( 100 )
{
}
Another solution is
class T1
{
enum
{
t = 100
};
public:
T1();
};
So t is initialised to 100 and it cannot be changed and it is private.
If a member is a Array it will be a little bit complex than the normal is:
class C
{
static const int ARRAY[10];
public:
C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};
or
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
Another possible way are namespaces:
#include <iostream>
namespace mySpace {
static const int T = 100;
}
using namespace std;
class T1
{
public:
T1()
{
cout << "T1 constructor: " << mySpace::T << endl;
}
};
The disadvantage is that other classes can also use the constants if they include the header file.
This is the right way to do. You can try this code.
#include <iostream>
using namespace std;
class T1 {
const int t;
public:
T1():t(100) {
cout << "T1 constructor: " << t << endl;
}
};
int main() {
T1 obj;
return 0;
}
if you are using C++10 Compiler or below then you can not initialize the cons member at the time of declaration. So here it is must to make constructor to initialise the const data member. It is also must to use initialiser list T1():t(100) to get memory at instant.
you can add static to make possible the initialization of this class member variable.
static const int i = 100;
However, this is not always a good practice to use inside class declaration, because all objects instacied from that class will shares the same static variable which is stored in internal memory outside of the scope memory of instantiated objects.
In C++ you cannot initialize any variables directly while the declaration.
For this we've to use the concept of constructors.
See this example:-
#include <iostream>
using namespace std;
class A
{
public:
const int x;
A():x(0) //initializing the value of x to 0
{
//constructor
}
};
int main()
{
A a; //creating object
cout << "Value of x:- " <<a.x<<endl;
return 0;
}
Hope it would help you!
I have a problem that can be minimized to the following example
#include <iostream>
#include <string>
class A{
public:
const char* chr;
A(){chr = "aaa";}
};
class B : A{
public:
const char* chr;
B(){chr = "bbb";}
};
template <class T>
std::string to_str(T) = delete;
template<>
inline std::string
to_str<A>(A object) {
std::string str;
return str.assign((object.chr));
}
int main() {
A a;
B b;
std::cout << to_str(b) << std::endl;
}
when changing it to std::cout << to_str(a) << std::endl; the code runs and prints 'aaa', but like this, it stops at compilation and outputs
main.cpp: In function 'int main()':
main.cpp:30:24: error: use of deleted function 'std::__cxx11::string to_str(T) [with T = B; std::__cxx11::string = std::__cxx11::basic_string<char>]'
std::cout << to_str(b) << std::endl;
^
main.cpp:18:13: note: declared here
std::string to_str(T) = delete;
^~~~~~
exit status 1
now lets say i have a lot of classes that inherit A, can i 'tell' the compiler they all can go to the same function (the one accepts A)?
Thanks.
can i 'tell' the compiler they all can go to the same function(the one accepts A)?
Yes, using SFINAE and std::is_base_of
template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
to_str (T const & t)
{ return t.chr; }
The following is a full working example
#include <type_traits>
#include <iostream>
#include <string>
struct A { char const * chr; A() : chr{"aaa"} {} };
struct B : A { char const * chr; B() : chr{"bbb"} {} };
struct C { char const * chr; C() : chr{"ccc"} {} };
template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
to_str (T const & t)
{ return t.chr; }
int main()
{
A a;
B b;
C c;
std::cout << to_str(a) << std::endl; // print aaa
std::cout << to_str(b) << std::endl; // print bbb
// std::cout << to_str(c) << std::endl; // compilation error
}
I question if this really is a minimized example of your problem. I think that what's happened is that some important details got lost in the translation, because the code you've shown us here has a number of issues.
B inherits privately from A. There is no way we can really treat a B like an A in this case.
If you changed inheritance to public, then we could attempt to force a B in like so:
class B : public A{/*...*/};
// ...
std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
But the output will remain "aaa", which leads me to my next points
Your to_str specialization for A accepts by value. This is important because even if we wanted to force a B in, we end up slicing the object, this matters because
B redefines the const char* chr effectively hiding A::chr, and since we've sliced, there's no way to recover B's chr.
We could start fixing things but first fixing the slicing by accepting A by reference instead (or const reference), and always preferring an overload instead of a template specialization for a function:
std::string to_str(A& object) {/*...*/}
The next problem is that there is no way direct to recover B's chr from an instance of A. We could go one of two ways here.
Use a std::string member in A and do not redeclare it in any derived class, then derived classes can set it on initialization.
Example:
class A{
public:
std::string chr;
A():chr{"aaa"}{}
};
class B : public A{
public:
B(){chr = "bbb";}
};
We write a virtual const char* get_char() method in A that derived classes can override.
Example:
class A{
public:
const char* chr;
A(){chr = "aaa";}
virtual const char* get_chr() const{return chr;}
};
class B : public A{
public:
const char* chr;
B(){chr = "bbb";}
const char* get_chr() const override {return chr;}
};
template <class T>
std::string to_str(T) = delete;
std::string to_str(A& object) {
std::string str;
return str.assign((object.get_chr()));
// ...
std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
Note that at this point we're still forcing each B to be an A, which leads me to my next point
template <class T> std::string to_str(T) = delete; will always exactly match every type you don't explicitly specialize for, being preferred in the worst case and causing ambiguity in the best case.
If you don't have any control over this function, then we're stuck with what we've got. However, if we do, then we can achieve what we need using type_traits to accept anything that is derived from A.
In this way we can keep your private inheritance, and also keep your redeclared chr member, while simultaneously disabling to_str for everything else and not requiring we static_cast our b.
Example:
#include <type_traits>
class A{
public:
const char* chr;
A(){chr = "aaa";}
};
class B : A{
public:
const char* chr;
B(){chr = "bbb";}
};
template<class T, class = std::enable_if_t<std::is_base_of<A, T>::value, int>>
inline std::string to_str(T& object) {
std::string str;
return str.assign((object.chr));
}
int main() {
A a;
B b;
std::cout << to_str(b) << std::endl;
}
Overall, I think that the best approach would be to give A a protected std::string chr that each derived class sets on initialization, and then have your to_string function that is specialized for A& (as an overload) print that member.
Edit: I forgot one last note. Issue #6: There are no virtual members in A. Therefore you will never be able to dynamic_cast a pointer to A to any derived class.
Template function specialization does not work that way. There is no overload resolution; it merely permits replacing a specific function body with specific template arguments with your specialized one. It is rarely useful.
What you want is overload resolution, possibly with tag dispatch.
First remove this completely:
template <class T>
std::string to_str(T) = delete;
next, write an overload:
inline std::string to_str(A object) {
std::string str;
return str.assign((object.chr));
}
and done. Overload resolution dispatches B to the A overload.
Your next problem is slicing. B has two members named chr: A::chr and B::chr. For no good reason. In addition you are needlessly copying A (or the A subobject of B).
inline std::string to_str(A const& object) {
std::string str;
return str.assign((object.chr));
}
this avoids a needless copy of A.
class A{
public:
const char* chr;
A(){chr = "aaa";}
};
class B : public A{ // public, not private
public:
// const char* chr; // no need for this
B(){chr = "bbb";}
};
According to 14.7.3 [temp.expl.spec] paragraph 1, only non-deleted function templates may be explicitly specialized
C++ Standard Core Language Defect Reports and Accepted Issues, Revision 97
So, if you change
template <class T>
std::string to_str(T) = delete;
in, for example,
template <class T>
std::string to_str(T) { return ""; }
everything should work
I compiled the code below using g++ 6.3.0, with -std=c++14 option.
#include <utility>
#include <iostream>
struct A{
int x;
A(const A&)=default;
A(int x):x(x){}
};
struct B{
A a;
template<class... Args>
B(Args&&... args):a(std::forward<Args>(args)...){
std::cout<<"1!"<<std::endl;
}
explicit B(const A& a):a(a){std::cout<<"2!"<<std::endl;}
};
struct C:B{
using B::B;
};
int main(){
A a{2};
const A& aref=a;
C c=aref; //Implicit conversion
}
I expected it to output "1!" since the conversion is implicit, but it output "2!". If I comment out the template constructor, it will not compile. Is this the correct behavior, or is this some kind of g++ bug?
Yes, your program shall print 1!.
A simplified version of the program showing compiler divergence is
struct B {
int b;
constexpr B(auto) { b = 1; }
constexpr explicit B(int) { b = 2; }
};
struct C : B {
using B::B;
};
constexpr B b = 0;
static_assert( b.b == 1 ); //ok everywhere
constexpr C c = 0;
static_assert( c.b == 1 ); //ok in Clang only
Demo: https://gcc.godbolt.org/z/hva4f5qs5
As quoted in related GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85251 : [namespace.udecl] p13 does specify what should happen here:
Constructors that are named by a using-declaration are treated as though they
were constructors of the derived class when looking up the constructors of the
derived class ([class.qual]) or forming a set of overload candidates
([over.match.ctor], [over.match.copy], [over.match.list]).
So explicit constructor from B shall remain explicit in C after using B::B;, and only Clang correctly process the above program at this moment.
And even easier way to see that other compilers are wrong, is to remove B(auto) constructor:
struct B {
int b;
constexpr explicit B(int) { b = 2; }
};
struct C : B {
using B::B;
};
constexpr C c = 0; // error everywhere
Now all compilers correctly reject the code (demo: https://gcc.godbolt.org/z/P3zqxMvvn) even though they did not call the removed constructor in the previous example.
Problem: source code (see. below) is compiled MSVC , but does not compile g++.
#include <iostream>
using namespace std;
class B;
class A
{
friend class B;
private:
int i;
A(int n) : i(n) { }
public :
A(A& a) { if (&a != this) *this = a; }
int display() { return i;}
};
class B
{
public :
B() { }
A func( int j) { return A(j); }
};
int main(int argc, char **argv)
{
B b;
A a(b.func((10)));
cout << " a.i = " << a.display() << endl;
return 0;
}
Output:
GNU g++ compilation message:
g++ -c main.cpp
main.cpp: In member function 'A B::func(int)':
main.cpp:25:38: error: no matching function for call to 'A::A(A)'
A func( int j) { return A(j); }
^
main.cpp:25:38: note: candidates are:
main.cpp:17:9: note: A::A(A&)
A(A& a) { if (&a != this) \*this = a; }
^
main.cpp:17:9: note: no known conversion for argument 1 from 'A' to 'A&'
main.cpp:14:9: note: A::A(int)
A(int n) : i(n) { }
^
main.cpp:14:9: note: no known conversion for argument 1 from 'A' to 'int'
main.cpp: In function 'int main(int, char\**)':
...
Why? Class B is a friend for class A then B has access to private constructor A(int i).
Your copy constructor must take a const reference so it can bind to a temporary A:
A(const A& a) { .... }
The C++ standard does not allow binding a non-const reference to a temporary. g++ is strict about this, while MSVC has an "extension" that breaks the rule.
Besides that, your implementation of the copy constructor looks strange. You should not be using the assignment operator there. For a class like A, you should use the implicitly generated copy constructor, in other words, remove your own:
class A
{
friend class B;
private:
int i;
A(int n) : i(n) { }
public :
int display() const { return i;}
};
It is a bug of MS VC++. It shall not compile the code. The problem is that the error message of g++ is not cllear enough.
In fact the compiler tries to elide using of a copy constructor and to build the object directly in 'a' using constructor A(int n);. But that it will be possible an appropriate copy constructor shall be available. As a temporary object should be copied (if the ilision would not be used) then the copy constructor shall have const reference to object. That is instead of A(A& a); your copy constructor shall be declared as A( const A& a); If you will make the changes then g++ will compile the code.
The most simple way to define copy constructor for your example is to write
A( const A & ) = default;
However I am not sure whether your MS VC++ compiler supports this feature.
How should I write a constructor for a class to initialize a member that is a const structure / has const fields?
In the following example, I define a constructor within structure B and it works fine to initialize it's const fields.
But when I try to use the same technique to initialize const fields of structure C within class A it doesn't work. Can someone please help me and rewrite my class A in a way, that it starts working?
#include <iostream>
class A
{
public:
struct C
{
C (const int _x) : x (_x) {}
const int x;
};
C c (3);
};
int main (int argc, char *argv[])
{
struct B
{
B (const int _x) : x (_x) {}
const int x;
};
B b (2);
std::cout << b.x << std::endl;
A a;
std::cout << a.c.x << std::endl;
return 0;
}
P.S.
I did some search and I think, I understand, that unless I have C++11 support or want to use boost library, I have to define a helper function to initialize a const struct within initialization list
(C++ Constant structure member initialization)
but it seems to be crazy that I have to define alike struct, but with non const fields to initialize a struct with const fields, doesn't it?
Another thing that I found tells that I should initialize const members in a constructor of the class A, rather than in a constructor of the struct C (C++ compile time error: expected identifier before numeric constant) but it also seems crazy to me, because why should I rewrite a class constructor every time I want to add a new struct, isn't it more convenient to have a separate constructor for each struct C within the class A?
I would be grateful to any comments that could possibly clarify my confusion.
I'd do the job like this:
#include <iostream>
class A {
public:
struct C {
C(const int _x) : x(_x) {}
const int x;
};
C c; // (3);
A() : c(3) {}
};
int main(int argc, char *argv []) {
A a;
std::cout << a.c.x << std::endl;
return 0;
}
Note that it's not a matter of using a ctor in A or in C, but of the ctor for A telling how the ctor for C should be invoked. If the value that will be passed will always be 3 that's not necessary, but I'm assuming you want to be a able to pass a value of your choice when you create the C object, and it will remain constant after that.
If the value will always be the same (3 in this case) you can simplify things a lot by also making the constant static:
struct A {
struct C {
static const int x = 3;
};
C c;
};
int main() {
A a;
std::cout << a.c.x << "\n";
}
So, if the value is identical for all instances of that class, make it static const, initialize it in place, and life is good. If the value is not known until you create an instance of the object, and remains constant thereafter for the life of that object, you need to pass it in through the constructors.
For a slightly different case, there's a third possibility: if C is an independent class (not nested inside of A) you might have a situation where other instances of C use various values, but all instances of C inside an A always use the same value. In this case, you'd do something like:
struct C {
const int x;
C(int x) : x(x) {}
};
struct A {
C c;
A() : c(3) {}
};
Of course, you can do the same thing when C is nested inside of A, but when/if you do, it generally means you're setting the same value for all instances of C, so you might as well use the static const approach instead. The obvious exception would be if A had multiple constructors, so (for example) A's default constructor passed one value for C::x and its copy constructor passed a different value.