Conversion between different template instantiation of the same template - c++

I am trying to write an operator which converts between the differnt types of the same implementation. This is the sample code:
template <class T = int>
class A
{
public:
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
private:
int m_a;
};
int main(void)
{
A<int> a;
A<double> b = a;
return 0;
}
However, it gives the following error for line u.m_a = m_a;.
Error 2 error C2248: 'A::m_a' :
cannot access private member declared
in class
'A' d:\VC++\Vs8Console\Vs8Console\Vs8Console.cpp 30 Vs8Console
I understand the error is because A<U> is a totally different type from A<T>. Is there any simple way of solving this (may be using a friend?) other than providing setter and getter methods? I am using Visual studio 2008 if it matters.

VC10 accepts this:
template <class T = int>
class A
{
public:
template< typename U>
friend class A;
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
private:
int m_a;
};

You can declare the conversion function as friend
template <class T = int>
class A
{
public:
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
template <class U> template<class V>
friend A<U>::operator A<V>();
private:
int m_a;
};

You could construct the A<U> with the int directly.

Related

Choosing template specialization of a base type with derived types

Is it possible to have the template specialization of a base type chosen for the derived types? If not, what is a possible solution to the following without having to specialize for each derived type?
NOTE: This is a simplified version of our validator. Different types have different validation requirements
template <typename T>
class IsValid_Executor
{
public:
auto IsValid(const T& InObj) -> bool = delete;
};
class Bar { };
class Foo : public Bar { };
template <>
class IsValid_Executor<void*>
{
public:
auto IsValid(const void* InObj)
{
return InObj != nullptr;
}
};
template <>
class IsValid_Executor<Bar*>
{
public:
auto IsValid(const Bar* InObj)
{
return InObj != nullptr;
}
};
template <typename T>
bool IsValid(const T& InObj)
{
return IsValid_Executor<T>{}.IsValid(InObj);
}
int main()
{
Bar* b;
IsValid(b); // compiles
Foo* f;
IsValid(f); // error: use of deleted function
IsValid_Executor<void*>{}.IsValid(f); // compiles
IsValid_Executor<decltype(f)>{}.IsValid(f); // error: use of deleted function - why isn't the void* OR the Bar* overload chosen?
IsValid_Executor<Bar*>{}.IsValid(f); // compiles - however, I cannot know in the `IsValid<T>` function to choose Bar*
}
You can use partial specialization for all the derived classes of Bar.
template <typename T, typename = void>
class IsValid_Executor
{
public:
auto IsValid(const T& InObj) -> bool = delete;
};
then
template <typename D>
class IsValid_Executor<D*, std::enable_if_t<std::is_base_of_v<Bar, D>>>
{
public:
auto IsValid(const Bar* InObj)
{
return InObj != nullptr;
}
};
LIVE

Why do I get "..::b is private within this context"

Here is the context.. I'm compiling with g++.
template<typename T>
class Array;
template<typename T>
int length(Array<T>& a);
template<typename T>
class Array
{
public:
//...
private:
T* a;
int b;
template<typename>
friend int length(Array<T>&);
};
template<typename T>
int length(Array<T>& a)
{
return a.b;
}
Is there a way to always declare "the corresponding friend length function" (i.e. length) if "the class is defined (i.e. Array)?
I thought maybe explicitely instantiate it like..
...
template<typename T>
class Array
{
public:
...
private:
...
template int length<T>(Array<T>&);
friend int length(Array<T>&);
};
...
NOTE: the above doesn't compile
Yes, you simply need to fix the declaration:
private:
T* a;
int b;
friend int length<>(Array<T>&);
It should be
template<typename T>
class Array
{
public:
//...
private:
T* a;
int b;
friend int length<>(Array&);
};
Demo
Your template<typename /*U*/> friend int length(Array<T>&); doesn't match outside template.
I think you can fix your code like this:
template<typename T>
class Array
{
public:
//...
int getB() { return b;};
private:
T* a;
int b;
template<typename>
friend int length(Array<T>&);
};
template<typename T>
int length(Array<T>& a)
{
return a.getB();
}

C++ template class operator overloading with the same signatures

A simple C++ OO question regrading templates and operator overloading: In the following class, I have overloaded the index operator twice:
template<class A, class B>
class test
{
A a1;
B a2;
public:
A& operator[](const B&);
B& operator[](const A&);
};
Now, if I instantiate an object of this template class with the same typenames:
test<int, int> obj;
calling the index operator will result in an error, because the two overloaded functions will have the same signatures.
Is there any way to resolve this issue?
Sorry, if this is a basic question. I am still learning!
You can add a partial specialization:
template<class A>
class test<A, A>
{
A a1, a2;
public:
A& operator[](const A&);
};
You can avoid this issue and make the code more robust and expressive by converting the index to some other type that clarifies what the user wants. Usage would be like this:
bidirectional_map<int, int> myTest;
int& valueFor1 = myTest[Key{1}];
int& key1 = myTest[Value{valueFor1}];
Implemented like this:
template<class TKey>
struct Key { const TKey& key; };
template<class TValue>
struct Value { const TValue& value; };
// Deduction guides (C++17), or use helper functions.
template<class TValue>
Value(const TValue&) -> Value<TValue>;
template<class TKey>
Key(const TKey&) -> Key<TKey>;
template<class TKey, class TValue>
class bidirectional_map
{
TKey a1; // Probably arrays
TValue a2; // or so?
public:
TValue & operator[](Key<TKey> keyTag) { const TKey & key = keyTag.key; /* ... */ }
TKey & operator[](Value<TValue> valueTag) { const TValue& value = valueTag.value; /* ... */ }
};
Now, Key and Value are popular names so having them "taken up" by these auxiliary functions is not the best. Also, this is all just a pretty theoretical exercise, because member functions are of course a much better fit for this task:
template<class TKey, class TValue>
class bidirectional_map
{
TKey a1; // Probably arrays
TValue a2; // or so?
public:
TValue& getValueForKey(const TKey& key) { /* ... */ }
TKey& getKeyForValue(const TValue& value) { /* ... */ }
};
In C++2a, you might use requires to "discard" the function in some case:
template<class A, class B>
class test
{
A a1;
B a2;
public:
A& operator[](const B&);
B& operator[](const A&) requires (!std::is_same<A, B>::value);
};
Demo
Here is an example solution using if constexpr that requires C++17:
#include <type_traits>
#include <cassert>
#include <string>
template <class A, class B>
class test
{
A a1_;
B b1_;
public:
template<typename T>
T& operator[](const T& t)
{
constexpr bool AequalsB = std::is_same<A,B>();
constexpr bool TequalsA = std::is_same<T,A>();
if constexpr (AequalsB)
{
if constexpr (TequalsA)
return a1_; // Can also be b1_, same types;
static_assert(TequalsA, "If A=B, then T=A=B, otherwise type T is not available.");
}
if constexpr (! AequalsB)
{
constexpr bool TequalsB = std::is_same<T,B>();
if constexpr (TequalsA)
return a1_;
if constexpr (TequalsB)
return b1_;
static_assert((TequalsA || TequalsB), "If A!=B, then T=A || T=B, otherwise type T is not available.");
}
}
};
using namespace std;
int main()
{
int x = 0;
double y = 3.14;
string s = "whatever";
test<int, int> o;
o[x];
//o[y]; // Fails, as expected.
//o[s]; // Fails, as expected
test<double, int> t;
t[x];
t[y];
//t[s]; // Fails, as expected.
return 0;
};

Accessing private member variables inside public member function

In function myfun is there a way to access rhs.var without writing a public function which returns var? Also, as I understand, this happens because rhs could be a different type... Is this correct?
#include <iostream>
template<class T>
class foo
{
private:
T var;
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs)
{
auto i = rhs.var; //BOOM
}
};
int main()
{
foo<int> a = 5;
foo<double> b = 2.2;
a.myfun(b);
}
Suggested Solutions
You could either provide a public accessor to your private member variable:
template<class T>
class foo {
T var;
public:
foo(T v) : var(v) {}
T getVar() const { return var; }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
template<class Type>
void myfun(foo<Type>& rhs) {
auto i = rhs.getVar();
^^^^^^^^
}
};
Or as already Dieter mentioned in the comments you could make your template class a friend:
template<class T>
class foo {
T var;
template <class> friend class foo;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs) {
auto i = rhs.var;
}
};
Overview
The reason why the template member function myfun is not granted access to private member variable var of class template foo is that the compiler interprets class foo<Type> and class foo<T> as completely different class types, even though they would originate from the same template class definition. Thus, as being different class types the one cannot access the private members of the other.
you can define the second type as fried like:
template<class T>
class foo
{
private:
T var;
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs)
{
auto i = rhs.var; //BOOM
}
template<class Type>
friend class foo;
};
live example

How to let a method access private members of other template class instances?

This extremely minimal example will fail to compile because A<int> cannot access the private member i in A<double>
template <class T>
class A {
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
I know that I can make all the template instances friends of each other (see: How to access private members of other template class instances?), but since I have only one method that requires the access (like in the example) I would prefer to limit the friendship to that method. Is this possible?
Yes, it's possible. Member functions can be designated as friends normally.
template <class T>
class A {
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
template <class F>
template <class U>
friend void A<F>::copy_i_from(const A<U> & a);
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
Live example (gcc one Ideone)
Note that unlike gcc, clang rejects the code. I cannot find anything in the standard that would make it invalid, though.
It seems that if you want to have a friend member function, the following won't work on clang:
template <class T>
class A {
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
template <class F>
template <class U> friend void A<F>::copy_i_from(const A<U> & a);
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
while it works on gcc.
The issue seems to be a clang's problem with representing friend class template for which the dependent name specifier cannot be resolved in the AST: http://llvm.org/klaus/clang/commit/8b0fa5241a0416fc50dfbb7e38f20e777f191848/ (still in trunk at the time of writing this).
Therefore you could go for the member function version above although it might not work on clang until this is figured out.
A plan-B solution is to have it a free templated friend function, although it might not be what you want (accepted by both cland and gcc):
#include <iostream>
using namespace std;
template <class T>
class A {
int i;
public:
template<class V, class U>
friend void copy_i_from(A<V>& t, const A<U> & a);
};
template<class V, class U>
void copy_i_from(A<V>& t, const A<U> & a){
t.i = a.i;
}
int main(void) {
A<int> ai;
A<double> ad;
copy_i_from(ai,ad);
return 0;
}
Example