I have this problem with template class. I want to make a constructor with another class as a parameter with a different type, but every time I try to initialize the attribute of the class I get error that it's private and I can't access it.
I would appreciate any help.
Here is the simple code:
template <typename Type>
class SomeClass {
Type p;
public:
SomeClass(Type x) { p = x; }
template <typename Type2>
SomeClass(SomeClass<Type2> k) { p = k.p; }
Type GetP() { return p; }
};
int main()
{
SomeClass<double> c(2.4);
SomeClass<int> c1(c);
std::cout << c1.GetP() << std::endl;
return 0;
}
Just declare the class as friend:
template <typename Type>
class SomeClass {
Type p;
public:
template <typename Type2> friend class SomeClass;
SomeClass(Type x) { p = x; }
template <typename Type2>
SomeClass(SomeClass<Type2> k) { p = k.p; }
Type GetP() { return p; }
};
LIVE DEMO
SomeType<T> and SomeType<U> are different type and so cannot access private (nor protected) member the other class.
In your case, you may use your getter:
template <typename Type2>
SomeClass(const SomeClass<Type2>& k) { p = k.GetP(); }
Live Demo
Related
Suppose I define a template T that uses a nested class of the template parameter P, as follows:
template<class P> class T
{
public:
T(P& p) : p(p) {}
P& p;
typename P::Nested& get_nested() { return p.nested; }
};
If I declare a class A that includes a nested class named Nested, I can define a variable of type T<A> with no problem:
class A
{
public:
class Nested
{
public:
int i;
};
Nested nested;
};
void test2a()
{
A a;
a.nested.i = 1;
T<A> t_a(a);
t_a.get_nested().i = 2;
}
Now, I want to declare a class B that, in the same way, includes a nested class named Nested and that inherits from T<B>, as follows:
class B : public T<B>
{
public:
class Nested
{
public:
int i;
};
Nested nested;
};
Compilation of the above code fails with error: "Nested is not a member of B"
I think I understand what's happening: at the time the template is entered, class B is incompletely defined because of inheritance.
However, I am wondering if there is any way to do such a thing...
Thanks for help.
You need to defer the resolution of the return type of get_nested until it is called.
One way to do this is to make the return type dependent on a template parameter:
template<typename unused = void>
typename std::conditional<false, unused, P>::type::Nested&
get_nested() { return p.nested; }
Another way (since C++14) is to use return type deduction:
auto& get_nested() { return p.nested; }
I was able to have your example compile with simply
template<class P> class T
{
public:
T(P& p) : p(p) {}
P& p;
auto& get_nested() { return p.nested; }
};
Another approach, exploiting the same trick as #ecatmur, but a bit simpler:
template<class R = P>
typename R::Nested& get_nested() { return p.nested; }
Similarly, here the compiler has to postpone evaluation of P::Nested until you call get_nested().
I'm currently playing around with templates in C++ and got stuck with template template parameters.
Lets say I have the following classes:
template<typename T>
struct MyInterface
{
virtual T Foo() = 0;
}
class MyImpl : public MyInterface<int>
{
public:
int Foo() { /*...*/ }
};
template< template<typename T> typename ImplType>
class MyHub
{
public:
static T Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
In essence I would like to have a static class like MyHub that accepts an implementation of MyInterface and provides certain static methods to use them like static T Foo().
Then I tried to use MyHub:
int main()
{
int i = MyHub<MyImpl>::Foo();
return 0;
}
Unfortunately I always end up getting an error saying that the type T (of static T Foo() in MyHub) does not name a type.
I would expect that it works because
the template parameter of the template parameter Impl is named T
MyHub is a templated class with one template parameter and contains a method Foo
So far I couldn't find a solution for this after digging through documentations and google results so I hope some of you can help me.
You can use typedefs. Also, since your implementation classes are not template class, there is no need for template template parameters.
#include <iostream>
#include <string>
template<typename T>
struct MyInterface
{
virtual T Foo() = 0;
typedef T Type;
};
class MyIntImpl : public MyInterface<int>
{
public:
int Foo() { return 2; }
};
class MyStringImpl : public MyInterface<std::string>
{
public:
std::string Foo() { return "haha"; }
};
template<class ImplType>
class MyHub
{
public:
static typename ImplType::Type Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
int main()
{
std::cout << MyHub<MyIntImpl>::Foo() << "\n"; // prints 2
std::cout << MyHub<MyStringImpl>::Foo() << "\n"; // print haha
return 0;
}
Here is an example.
MyImpl is not a class template; so can't be passed as the template parameter of MyInterface.
You could change your MyInterface, MyImpl and MyHub classes to:
template<typename T>
class MyInterface{
public:
virtual T foo() = 0;
};
class MyImpl: public MyInterface<int>{
public:
using value_type = int;
value_type foo(){ return 1; /* dummy */ }
};
template<typename Impl, typename = std::enable_if_t<std::is_base_of<Impl, MyInterface<typename Impl::value_type>>::value>>
class MyHub{
public:
static auto foo(){
static Impl i;
return i.foo();
}
};
Which lets you use it the same way you are in your example.
The std::is_base_of check might be a little unnecessary in this case; but, this way you can't accidentally pass in another class that isn't derived from MyInterface with a method foo().
The STL uses value_type as a place holder for the underlying type of a template class. You could possibly do the same for your solution.
template<typename T>
struct MyInterface
{
typedef T value_type;
virtual T Foo() = 0;
}
class MyImpl : public MyInterface<int>
{
public:
int Foo() { /*...*/ }
};
template<typename ImplType>
class MyHub
{
public:
static typename ImplType::value_type Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
Also note that in c++14, typename ImplType::value_type can be replaced by auto:
static auto Foo()
{
ImplType i;
return i.Foo();
}
The names of template parameters of template template parameters are effectively a purely documentational construct—they don't get included in the containing template's scope.
There's good reason for that: there is nothing to whcih they could refer in the containing template. When you have a template template parameter, you must pass a template as the argument to it, and not an instantiation of a template. In other words, you're passing a template without arguments as the argument.
This means your code is simply wrong—you're using MyImpl as an argument for MyHub, but MyImpl is a class. MyHub expects a template, not a class. The correct instantiation of MyHub would be MyHub<MyInterface>. Not that there are no template arguments after this use of MyInterface; we are passing in the template itself, not an instantiation of it.
Template template parameters are used rather rarely in practice. You only use them if you want to instantiate the parameter template with your own types. So I would expect your MyHub code to do something like this:
template <template <class> class ImplTemplate>
struct MyHub
{
typedef ImplTemplate<SomeMyHub_SpecificType> TheType;
// ... use TheType
};
This doesn't seem to be what you want to do. I believe you want a normal type template parameter, and provide a nested typedef for its T. Like this:
template <class T>
struct MyInterface
{
typedef T ParamType; // Added
virtual T Foo() = 0;
};
template<class ImplType>
class MyHub
{
typedef typename ImplType::ParamType T;
public:
static T Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
int main()
{
int i = MyHub<MyImpl>::Foo();
return 0;
}
I'm writing a wrapper class to be derived which hides the implementation. How can I get the signature of the given template parameter's function?
template <class T>
struct wrapper
{
static typename std::result_of<&T::impl>::type
call(...) { // this function has the same signature of T::impl();
// here goes the jobs to do, such as logging or something
return T::impl(...);
}
};
struct sum : public wrapper<sum>
{
private:
friend class wrapper<func>
static int impl(int a, int b, int c) {
return a + b + c;
}
};
int main()
{
bind_to(&sum::call); // set binding
std::cout << sum::call(1,2,3) << std::endl;
}
Use a parameter pack:
template <class T>
struct wrapper
{
template <typename... Args>
auto call(Args&&... args) -> decltype(T::impl(std::forward<Args>(args)...))
{
return T::impl(std::forward<Args>(args)...);
}
};
Given the following declaration:
template<class T>
class A {
void run(T val) {
val.member ...
}
}
This code works fine if no pointers are used:
A<Type> a;
Type t;
a.run(t);
But using a pointer results in an error:
A<Type*> a;
Type* t = new Type();
a.run(t);
error: request for member ‘member’ which is of non-class type ‘T*’
Obviously in this case the member must be accessed via ->. What's the best way to handle this?
I found a solution on SO: Determine if Type is a pointer in a template function
template<typename T>
struct is_pointer { static const bool value = false; };
template<typename T>
struct is_pointer<T*> { static const bool value = true; };
...
if (is_pointer<T>::value) val->member
else val.member
But this is very verbose. Any better ideas?
You could use a simple pair of overloaded function templates:
template<typename T>
T& access(T& t) { return t; }
template<typename T>
T& access(T* t) { return *t; }
And then use them this way:
access(val).member = 42;
For instance:
template<typename T>
struct A
{
void do_it(T& val)
{
access(val).member = 42;
}
};
struct Type
{
int member = 0;
};
#include <iostream>
int main()
{
A<Type> a;
Type t;
a.do_it(t);
std::cout << t.member << std::endl;
A<Type*> a2;
Type* t2 = new Type(); // OK, I don't like this, but just to show
// it does what you want it to do...
a2.do_it(t2);
std::cout << t2->member;
delete t2; // ...but then, don't forget to clean up!
}
Here is a live example.
The best idea is probably to specialize your class for pointer types.
template<class T>
class A{ ...};
template<>
class A<T*> { //implement for pointers
};
If you feel that this is too verbose, you can use overload a get_ref function:
template<class T> T& get_ref(T & r) {return r;}
template<class T> T& get_ref(T* r) {return *r;}
template<class T>
class A {
void do(T val) {
get_ref(val).member ...
}
}
Is it possible to hide some member functions in a template class?
Let's imagine we have something like:
template <class T>
class Increment
{
public:
void init(T initValue)
{
mValue = initValue;
}
T increment()
{
++mValue;
}
T increment(T delta)
{
mValue += delta;
}
private:
T mValue;
};
The objective is to use this class in a way that, in certain cases
we only see the increment() function and in some other cases
we only see the increment(T) member function.
To do that, I can think about something with SFINAE:
class MultipleIncrement
{
typedef int MultipleIncrement_t;
};
class SingleIncrement
{
typedef int SingleIncrement_t;
};
template <class T, class Q>
class Increment
{
public:
void init(T initValue)
{
mValue = initValue;
}
T increment(typename Q::SingleIncrement_t = 0)
{
++mValue;
}
T increment(T delta, typename Q::MultipleIncrement_t = 0)
{
mValue += delta;
}
private:
T mValue;
}
And then use my template like, for example:
Increment<long, MultipleIncrement>
However, the compiler is not letting me do this.
Is there any other way in which this is feasible?
Would it also work if the member function is actually the constructor?
In this case, I would prefer using template specialization. Would something like this help you?
struct SingleIncrement;
struct MultipleIncrement;
template <
class T,
class Policy = SingleIncrement // default template param
>
class Increment
{
T mValue;
public:
Increment(T initValue)
: mValue(initValue)
{}
T increment()
{
++mValue;
}
};
// template specialization for MultipleIncrement
template <class T>
class Increment<T,MultipleIncrement>
{
T mValue;
public:
Increment(T initValue)
: mValue(initValue)
{}
T increment(T delta)
{
mValue += delta;
}
};
Template specialization is good. Inheritance sounds better. Have you considered templating on the inherited base class? (Or is this now considered a faux pax?)
#define SHOW(X) cout << # X " = " << (X) << endl
template <class T>
class A
{
public:
void foo(T t) {SHOW(t); }
};
template <class T, class BASE>
class B : public BASE
{
public:
void bar(T t) {SHOW(t); }
};
int
main()
{
B<int,A<int> > b;
b.foo(1);
b.bar(2);
}
Here is a MWE of how this could be achieved:
#include <iostream>
using namespace std;
struct multi;
struct single;
template<class T, class Q>
struct dummy {
dummy(T value) : m_value(value) { }
// using enable_if_t in template argument
template<class _Q = Q, enable_if_t<is_same<_Q, single>::value && is_same<_Q, Q>::value, int> = 1>
T increment() { return ++m_value; }
// using enable_if_t in method return type
template<class _Q = Q>
enable_if_t<is_same<_Q, multi>::value && is_same<_Q, Q>::value, T>
//enable_if_t<is_same<_Q, multi>::value, T> // (*)
increment(T delta) { return (m_value += delta); }
T m_value;
};
int main() {
dummy<double, multi> m(47.10);
//cout << m.increment() << endl; // error as expected
cout << m.increment(.01) << endl;
dummy<int, single> s(41);
cout << s.increment() << endl;
cout << s.increment<single>() << endl;
//cout << s.increment(1) << endl; // error as expected
//cout << s.increment<multi>(1) << endl; // not an error when using (*)
}
Output
Using c++ (Debian 6.2.1-5) 6.2.1 20161124 this yields:
47.11
42
43
Elaboration
We need to template the methods to make SFINAE work at all. We cannot use something like
std::enable_if_t<std::is_same<_Q, multiple_increment>::value, T> increment() ...
because that fails when instantiating the template dummy<T, single_increment> instead of failing when substituting method template parameters.
Further, we want the user to be able to use the methods without actually providing a method template parameter. So we make the method template parameter _Q default to Q.
Finally, to really force a compiler error when using the unwanted method even when providing a method template parameter, we only enable_if_t the method if method template parameter _Q is actually the same type as the respective class template parameter Q.