I have a nested private classes Nested and Key and I want that I could using my add_new_object(Key, Nested) function add objects to my my_mmap multimap. But when I try to call that those classes constructors, obviously that it's inaccessible. How can I solve the problem.
class Enclosing
{
private:
class Nested {
string m_str;
double m_dbl;
bool m_boolean;
public:
Nested(string str, double dbl, bool boolean) :m_str(str), m_dbl(dbl), m_boolean(boolean) {};
};
class Key {
int m_number;
string m_name;
public:
Key(int num, string name) :m_number(num), m_name(name) {};
};
Enclosing* singleton;
std::multimap<Key, Nested> my_mmap;
public:
void add_new_object_to_mmap(Key k, Nested n) {}
static Enclosing* get_singleton() {
static Enclosing instance;
return &instance;
}
};
Thank you all in advance!
You seem to misunderstand what it means to declare a type in the private section. Or at least you are not aware of the implications of those types appearing as arguments of a public member function.
Here is your code with definitions added (without a definition for Key and Nested you cannot call their constructor at all):
#include <map>
class Enclosing
{
private:
class Nested {};
class Key {};
Enclosing* singleton;
std::multimap<Key, Nested> my_mmap;
public:
void add_new_object_to_mmap(Key k, Nested n) {}
static Enclosing* get_singleton() {
static Enclosing instance;
return &instance;
}
};
Because the type Key and Nested appear in the public interface of Enclosing they are not actually private. Only their names are private. It is possible to infer the two types from the member function:
template <typename F> struct get_types;
template <typename K,typename N> struct get_types< void(Enclosing::*)(K,N)> {
using Key = K;
using Nested = N;
};
Now you can call their constructor like you call the constructor of any other type:
int main()
{
using Types = get_types<decltype(&Enclosing::add_new_object_to_mmap)>;
using Key = Types::Key;
using Nested = Types::Nested;
Enclosing::get_singleton()->add_new_object_to_mmap(Key{},Nested{});
}
Complete Example
Finally, note that the caller doesn't even have to have names for the two types. This works as well (or with parameters when there are no default constructors):
Enclosing::get_singleton()->add_new_object_to_mmap({},{});
A type declared in the private section of another class is not private when it appears in the public interface. If you really wanted to hide the two types from the user of Enclosing then you need to do something else. See Teds answer for how to pass only parameters to be passed to their constructor to the public add_new_object_to_mmap. Then the two types can be truly private.
If you only need to be able to construct Key and Nested using a constructor taking 1 argument each, you could make add_new_object_to_mmap into a member function template and forward the arguments to the actual constructors:
#include <utility>
class Enclosing {
private:
class Key {
public:
Key(int);
bool operator<(const Key& rhs) const;
// ...
};
class Nested {
public:
Nested(double);
// ...
};
std::multimap<Key, Nested> my_mmap;
public:
template<class Karg, class Narg>
void add_new_object_to_mmap(Karg&& karg, Narg&& narg) {
my_mmap.emplace(std::forward<Karg>(karg), std::forward<Narg>(narg));
}
static Enclosing& get_singleton() {
static Enclosing instance;
return instance;
}
};
int main() {
/*here I want to call constructors*/
Enclosing::get_singleton().add_new_object_to_mmap(1, 3.141);
}
Demo
To support constructing Key and Nested with a variable amount of arguments, you could use std::piecewise_construct:
template <class... Args>
void add_new_object_to_mmap(Args&&... args) {
my_mmap.emplace(std::piecewise_construct, std::forward<Args>(args)...);
}
and forward the arguments as tuples:
int main() {
Enclosing::get_singleton().
add_new_object_to_mmap(std::forward_as_tuple(1, "Foo"),
std::forward_as_tuple("Str", 3.141, true));
}
Demo
Related
I am not sure what to call it, but is something like this possible as the commented out line reflects?
template <typename T>
class Test
{
public:
Test(T& t) : m_t(t) {}
T* operator->() { return &m_t; }
private:
T& m_t;
};
class A
{
public:
static const int integer = 0;
void function() {}
};
int main()
{
A a;
Test<A> test(a);
test->function();
// Something similar to doing Test<A>::integer?
return 0;
}
Well, why don't you do:
test->integer;
You can always access static members the same way as non-static ones (i.e. from an instance variable).
The other option would be to define in Test:
template <typename T>
class Test
{
public:
typedef T value_type;
// ...
};
In which case you will be able to do:
Test<A>::value_type::integer;
which will avoid the need of creating an instance of Test<A>.
At last, if you are using C++11 and Test follows the smart pointers conventions, then you will have:
std::pointer_traits<Test<A> >::element_type::integer;
which has the advantage to work even if you replace Test<A> with A*.
No. In C++, "overloading" only makes sense for functions. Instead of mixing static and non-static items in a class, you could try making two separate classes, both with all non-static members. Return your value from a function call, rather than using a public static member variable.
I have this class template
template <typename T>
class Wrapper
{
public:
virtual void parse(std::string s) = 0;
protected:
T value;
};
ideally, each type should know how to parse itself from a string, so I would like to have, for instance, specializations such as
template<>
class Wrapper<int>
{
public:
virtual void parse(std::string s)
{
value = atoi(s.c_str());
}
};
however, apparently, I can't access the "value" member from the main template. What I get is something like:
In member function 'virtual void Wrapper<int>::parse(std::string)':
error: 'value' is not a member of 'Wrapper<int>'
adding this-> in front of value doesn't help.
Do you have any idea how to fix this?
Thanks
The various specializations of class template are completely unrelated to each other. Wrapper<int> does not know anything about e.g. Wrapper<char>. So you need to separately define the data members for each specialization
template<>
class Wrapper<int>
{
public:
virtual void parse(std::string s)
{
value = atoi(s.c_str());
}
protected:
int value;
};
There is also the question of the virtual keyword in front of parse(). You do not need it here unless you intend Wrapper<int> to be a base class that can have its parse() method redefine by subsequent derived classes. If all you are going to do is create various Wrapper<> specializations, then you should not make parse() virtual.
I think I solved it, the trick is to specialize only the member functions, not the whole class
template<>
void Wrapper<int>::parse(std::string s)
{
this->value = atoi(s.c_str());
}
I have a socket data type class that is used to read and parse a value from socket stream (may be used for file too).
Let my class be mc_double:
class mc_double {
private:
double value;
public:
bool read(socket);
write(double);
}
Actual class is more complicated, but this is the principle. Now, I need to parse float from the stream. Float is way similar to double, so is already implemented int. Could't I merge this class definitions, with all double, int and float somehow templated?
This is what I mean:
class mc_<typename = double or int or float> {
private:
typename value;
public:
bool read(socket);
write(typename);
}
Some methods would be then defined individualy as mc_double::method() others would be same for all types: mc_typename::general_method(). Also, for some I'd need just minor changes in code:
typename mc_typename::return_value() {
return val;
}
Or the constructor:
mc_typename::mc_typename(<int, long, char, double> number) {
val = (typename)number;
}
The result should be three classes - mc_int, mc_float and mc_double.
I have found the official C++ template docs, but I only figured out the last part of my question - I can create a function that accepts multiple data types. The rest does not seem to be that easy.
You could make your class a class template:
template<typename T, bool base = true>
class mc {
protected:
T value;
public:
bool read(socket);
write(T);
};
This class will contain the member function that are common for all types T. Then, you could specialize this class templates separately for different types and let them inherit from mc<T, true>:
template<>
class mc<double, true> : public mc<double, false> {
public:
// Member functions for double only...
};
template<>
class mc<int, true> : public mc<int, false> {
public:
// Member functions for int only...
};
Make sure the non-public member data of the primary class template are made protected if you want derived classes to access them.
You could then instantiate them this way:
mc<double> m;
mc<int> m;
// ...
If you really want to use the mc_double and mc_int names, then you could either:
a) Create type aliases for them:
typedef mc<double> mc_double;
typedef mc<int> mc_int;
b) Change the design of the class template to not use specialization and have one single template parameter, and create the derived classes independently:
template<typename T>
class mc {
protected:
T value;
public:
bool read(socket);
write(T);
};
class mc_double : public mc<double> {
public:
// Member functions for double only...
};
class mc_int: public mc<int> {
public:
// Member functions for int only...
};
You could use templates in the class definition as follows:
template <typename T>
class mc
{
public:
bool write(T _val);
private:
T mVal;
};
but you can't as easily specialize some methods but not others based on the type of T (i.e., you have to specialize the entire class, not just one method). You could solve this with some sort of inheritance hierarchy, where methods that are the same regardless of the type are in the base, and the specialization is in derived classes. So keep the above (assuming write is one that doesn't change) and create:
class mc_double : public mc<double>
{
public:
void doSomethingSpecific() { /* code specific for 'doubles' */ }
};
Consider the following situation in C++:
template<int n>
class Base { ... };
class Derived3 : public Base<3> {
// a complicated body, making use of n=3
};
class Derived7 : public Base<7> {
// a completely different body, making use of n=7
};
Inside of the Derived3 member functions, I would like to explicitly use n=3, and inside Derived7, n=7, without hardcoding the numbers, i.e., still referring to something like a template argument n. The following options come to my mind:
Also templating the derived classes on n, and then using typedef. This way, the derived classes know n:
template<int n>
class DerivedTemplate3 : public Base<n> { ... };
typedef DerivedTemplate3<3> Derived3;
template<int n>
class DerivedTemplate7 : public Base<n> { ... };
typedef DerivedTemplate7<7> Derived7;
The problem with this is that DerivedTemplateX makes sense for nothing but n=X, so this feels like abusing the template paradigm.
Using a static const member to store n in Base, and referring to that in the derived classes:
template<int n>
class Base {
protected:
static const int nn = n;
...
};
class Derived3 : public Base<3> {
// refer to nn=3
};
class Derived7 : public Base<7> {
// refer to nn=7
};
The problem here is that I seemingly can't use the same identifier (nn vs. n). Also, I'm not sure whether this will allow me to use nn as a template argument for members of the derived classes.
So: how can this be implemented in a non-redundant, efficient way? Maybe using some kind of static const int as a member somewhere?
The standard practice is to use an uppercase letter for the template parameter, then a static const value in lowercase:
template<int N>
class Base {
protected:
static const int n = N;
...
};
Then you use the lowercase static const value n everywhere - don't use N anywhere else.
Also, I'm not sure whether this will allow me to use nn as a template argument for members of the derived classes.
It is a constant expression and so it can be used as a template argument.
Does this work for you?
template<int n>
class Base {
protected:
static const int MyN = n;
};
class Derived3 : public Base<3> {
void f()
{
std::cout << MyN;
}
};
class Derived7 : public Base<7> {
void f()
{
std::cout << MyN;
}
};
int main()
{
}
Having a class like this:
class A {
public:
bool hasGrandChild() const;
private:
bool hasChild() const;
vector<A> children_;
};
Why is it not possible to use a private method hasChild() in a lambda expression defined in the method hasGrandChild() like this?
bool A::hasGrandChild() const {
return any_of(children_.begin(), children_.end(), [](A const &a) {
return a.hasChild();
});
}
Compiler issues an error that the method hasChild() is private within the context. Is there any workaround?
Edit:
It seems that the code as I posted it originally works. I thought that it is equivalent, but the code that does not work on GCC is more like this:
#include <vector>
#include <algorithm>
class Foo;
class BaseA {
protected:
bool hasChild() const { return !children_.empty(); }
std::vector<Foo> children_;
};
class BaseB {
protected:
bool hasChild() const { return false; }
};
class Foo : public BaseA, public BaseB {
public:
bool hasGrandChild() const {
return std::any_of(children_.begin(), children_.end(), [](Foo const &foo) {
return foo.BaseA::hasChild();
});
}
};
int main()
{
Foo foo;
foo.hasGrandChild();
return 0;
}
Seems that there is a problem with fully qualified names as this does not work, but this works.
It seems to be just a GCC bug in a special case when the lambda tries to access a protected member from parent class using fully qualified name. This does not work:
class Base {
protected:
bool hasChild() const { return !childs_.empty(); }
std::vector<Foo> childs_;
};
class Foo : public Base {
public:
bool hasGrandChild() const {
return std::any_of(childs_.begin(), childs_.end(), [](Foo const &foo) {
return foo.Base::hasChild();
});
}
};
, but this works:
class Foo : public Base {
public:
bool hasGrandChild() const {
return std::any_of(childs_.begin(), childs_.end(), [](Foo const &foo) {
return foo.hasChild();
});
}
};
According to C++11, 5.1.2/3:
The type of the lambda-expression (which is also the type of the
closure object) is a unique, unnamed non-union class type — called the
closure type — whose properties are described below. This class type
is not an aggregate (8.5.1). The closure type is declared in the
smallest block scope, class scope, or namespace scope that contains
the corresponding lambda-expression.
And then C++11, 11.7/1:
A nested class is a member and as such has the same access rights as
any other member.
So the mentioned function-local lambda should have the same access rights as any other member of the class. Therefore it should be able to call a protected method from a parent class.
The standard (C++11, §5.1.2/3) states that
The type of the lambda-expression (which is also the type of the
closure object) is a unique, unnamed non-union class type — called
the closure type.
Since it's a unique class type that is not a friend of A, it doesn't have access to A's private members.
What the compiler does here is create a class type that has appropriate members to store any captured variables, an appropriate operator() etc -- which is exactly what you would write yourself if you wanted to emulate lambdas in C++03. This type would certainly not have access to private members, which might make it easier to visualize why the limitation exists and why there is no workaround.
Update regarding possible workarounds:
It would be better to say "there are no workarounds using a lambda", because in general workarounds do exist although they require that you forgo the convenient lambda syntax. For example, you could:
Write a local class type that explicitly captures this along with any other locals it requires (inspired by Björn Pollex's comment below).
Write a private method instead of a lambda and pass that as the callback (e.g. using std::bind for convenience). If you want to capture locals in addition to this you can use more std::bind at the call site to do so.
Workaround:
typedef bool (A::*MemFn)(void) const;
bool A::hasGrandChild() const {
MemFn f = &A::hasChild;
return any_of(childs_.begin(), childs_.end(), [=](A const &a) {
return (a.*f)();
});
}
You can capture this explicitly and make it a "member lambda" that has access to private members.
For example, consider the following sample:
#include <iostream>
class A {
private:
void f() { std::cout << "Private"; }
public:
void g() {
[this] {
f();
// doesn't need qualification
}();
}
};
class B {
private:
void f() { std::cout << "Private"; }
public:
void g() { [] { f(); }(); } // compiler error
};
int main() {
A a;
a.g();
}
It isn't possible because the lambda is not a part of the class. It's the same as making an out-of-class function, and calling it instead of creating a lambda. Of course it doesn't have access to private members.