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
Related
I have an interface class (IBase) that should contain typecasts to its children. The children are templates:
template <typename T>
class Derived1 : public IBase
{
private:
T m_1{};
public:
Derived1(T arg) : m_1{ arg } {}
template <typename T>
operator Derived1<T>() { return *this; }
template <typename T>
operator Derived2<T>() { return { m_1 }; }
};
template <typename T>
class Derived2 : public IBase
{
private:
T m_2{};
public:
Derived2(T arg) : m_2{ arg } {}
template <typename T>
operator Derived1<T>() { return { m_2 }; }
template <typename T>
operator Derived2<T>() { return *this; }
};
The caller should be able to cast any derived class to another:
int main()
{
Derived1<double> d1{ 0.0 };
auto d2{ static_cast<Derived2<int>>(d1) };
}
This is where I'm stuck. I've tried using templates for the typecast operators, but I couldn't make them pure virtual:
class IBase
{
public:
template <typename T>
virtual operator Derived1<T>() = 0; // C2898: 'IBase::operator Derived1<T>(void)': member function templates cannot be virtual
template <typename T>
virtual operator Derived2<T>() = 0;
};
I've also tried not using templates, but the compiler wants a template argument list:
class IBase
{
public:
virtual operator Derived1() = 0;
virtual operator Derived2() = 0;
};
In reality, I have a class IColor with children RGBColor, HSVColor, etc. Is there a way to get this to work? Or is there a better alternative altogether?
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
For example, I have a class template:
template <typename T>
class base {
public:
void set(T data) { data_=data; }
private:
T data_;
};
And for a certain type I would like to add a function, but also have functions from the template class.
template <>
class base<int>{
public:
void set(int data) { data_=data; }
int get(){ return data_;} //function specific to int
private:
int data_;
}
How to do that without copying all members from the template class?
With inheritance:
template <typename T> struct extra {};
template <> struct extra<int> {
public:
int get() const;
};
template <typename T>
class base : public extra<T> {
friend class extra<T>;
public:
void set(T data) { data_=data; }
private:
T data_ = 0;
};
int extra<int>::get() const{ return static_cast<const base<int>*>(this)->data_;}
Demo
You can do this by using enable_if from type_traits to enable the get function only when the template parameter is int. One example is shown below.
#include <type_traits>
template <typename T>
class base {
public:
template <typename X=T,
std::enable_if_t< std::is_same<X,typename T>::value
&& std::is_same<X,int>::value, bool> = false>
int get() { return data_; }
void set(T data) { data_=data; }
private:
T data_;
};
Problem
Motivated by Sean Parent's "Runtime Polymorphism" I implemented a Serializable class that uses type-erasure to dispatch Serializable::serialize(...) ⟶ obj.serialize(...), where obj is a wrapped object.
struct Serializable
{
template <typename T>
Serializable(T obj)
: m_self(std::make_unique<Model<T> >(std::move(obj))) {}
/// Writes itself to a write storage
void serialize(Storage& outStream)
{ return m_self->serialize(outStream); }
private:
struct Concept
{
virtual ~Concept() = default;
virtual void serialize(Storage& outStream) = 0;
};
template <typename T>
class Model final : public Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ m_data.serialize(outStream); }
private:
T m_data;
};
private:
std::unique_ptr<Concept> m_self;
};
Now I would like to extend Serializable with another model class that would dispatch Serializable::serialize(...) to a free function with obj as an argument: Serializable::serialize(...) ⟶ serialize(obj, ...)
Then I would like a template constructor of Serializable to decide which model to use by checking the existence of either T::serialize(...) or serialize(const T&, ...)
Question
Is it possible by any means (e.g., SFINAE) to automatically construct Serializable so that it uses a method serialization if possible and free-function serialization otherwise?
Feel free to use any C++ standard up to C++17.
You can devise your own trait to find out whether the class has the correct serialize member. There are several ways to do it, this is one of them:
template <class T, class = void>
struct HasMemberSerialize : std::false_type
{};
template <class T>
struct HasMemberSerialize<T, std::void_t<decltype(std::declval<T>().serialize(std::declval<Storage&>()))>> : std::true_type
{};
[Live example]
Then, add a new template parameter to Model and use the trait to find its argument:
struct Serializable
{
template <typename T>
Serializable(T obj)
: m_self(std::make_unique<Model<T, HasMemberSerialize<T>::value> >(std::move(obj))) {}
/// Writes itself to a write storage
void serialize(Storage& outStream)
{ return m_self->serialize(outStream); }
private:
struct Concept
{
virtual ~Concept() = default;
virtual void serialize(Storage& outStream) = 0;
};
template <typename T, bool Member>
class Model;
private:
std::unique_ptr<Concept> m_self;
};
template <typename T>
class Serializable::Model<T, true> final : public Serializable::Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ m_data.serialize(outStream); }
private:
T m_data;
};
template <typename T>
class Serializable::Model<T, false> final : public Serializable::Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ serialize(m_data, outStream); }
private:
T m_data;
};
So I have a class inside a foo namespace, which includes a friend function. Now I want the definition of the friend function to be in a different namespace bar so it can be called the way you see below. The error I get is that the private member val cannot be accessed.
Question: Why?
#include <iostream>
namespace foo
{
template<typename T>
class myclass
{
private:
T val;
public:
myclass(T v) : val(v) {}
template<class U>
friend void myfun(myclass<U>);
};
namespace bar
{
template<class U>
void myfun(myclass<U> a)
{
std::cout << a.val;
}
} //bar
} //foo
int main()
{
foo::myclass<int> a(5);
foo::bar::myfun(a);
}
You should declare foo::bar::myfun before the friend declaration and use appropriate namespace qualification (bar::):
namespace foo
{
template<typename T>
class myclass;
namespace bar
{
template<class U>
void myfun(myclass<U> a);
} //bar
template<typename T>
class myclass
{
private:
T val;
public:
myclass(T v) : val(v) {}
template<class U>
friend void bar::myfun(myclass<U>);
};
} //foo
Otherwise another function called myfun will be declared in the foo namespace by the friend declaration.