Change property access based on template argument - c++

I have a base class that is a template that looks like this:
template <typename T>
class Foo
{
public:
T bar;
};
What I'd like to do is introduce a template argument that can be used to control the access mode of the member bar.
Something like this:
template <typename T,bool publicBar=true>
class Foo
{
public:
// If publicBar is false, insert protected: here
T bar;
};
Is this possible?
Thanks.
Edit:
Many asked so, for those interesting in why I'm doing this, here's my real code!
// Class used for automatic setter/getter generation.
template <typename T,publicSetter=true>
class Property
{
public:
Property(){}
Property(T value):mObject(object){}
T operator()()const
{
return mObject;
}
public: // This is where I want the protected:
virtual void operator()(T newObject)
{
this->mObject = newObject;
}
private:
T mObject;
};

This can be done using partial template specialization:
template <typename T,bool publicBar>
class Foo
{
};
template <typename T>
class Foo<T,true>
{
public:
T bar;
};
template <typename T>
class Foo<T,false>
{
protected:
T bar;
};
The only gotcha here is that you would need to replicate the entire class for each specialization... UNLESS you wanted to make it on top of a base class, e.g.:
template <typename T>
class FooBase
{
//the goods go here
};
template <typename T,bool publicBar>
class Foo : public FooBase<T>
{
};
template <typename T>
class Foo<T,true> : public FooBase<T>
{
public:
T bar;
};
template <typename T>
class Foo<T,false> : public FooBase<T>
{
protected:
T bar;
};

Yes, this is possible using partial specialization. Whether it's advisable is a another question - for a start, this solution doesn't scale as you need 2^n specializations where n is the number of variables you're controlling the access of. And do you really want the interface of your class to change based on the value of a template parameter?
It seems like you're creating something difficult to maintain, difficult to understand and overly clever.
Nevertheless, if you decide this is a good idea, here's how you would do it:
template <typename T, bool publicBar=true>
class Foo
{
public:
T bar;
};
template <typename T>
class Foo<T,false>
{
protected:
T bar;
};

Yes, using explicit class template specialization:
template<bool B> class Foo;
template<> class Foo<true>
{
public:
int n_;
};
template<> class Foo<false>
{
protected:
int n_;
};
int main()
{
Foo<true> fa;
fa.n_;
Foo<false> fb;
fb.n_; // ERROR: protected
}
Seems like a really bad idea, though. Why would you want to?

I think you could do this with a template specialization. Totally untested code.
template <typename T,bool publicBar=true>
class Foo
{
public:
// If publicBar is false, insert protected: here
T bar;
};
template <typename T, false>
class Foo
{
protected:
// If publicBar is false, insert protected: here
T bar;
};
But really consider why you'd want to do this. public data is really dangerous for encapsulation, and protected is nearly so. A solution that's able to utilize a client-API will probably be more maintainable in the long-term.

How about
template<typename T>
struct FooBase {
T bar;
};
template<typename T, bool publicBar>
class Foo : public FooBase<T> {};
template<typename T>
class Foo<T, false> : protected FooBase<T> {};
This way you don't have to define bar a number of times but only once.

Related

What is the right way to implement this templated decorator pattern for this situation?

template <typename T> class FooBase {
void push(T& t) = 0;
T pop() = 0;
}
template<typename T> class FooDerived1: public FooBase<T> {
}
template<typename T> class FooDerived2: public FooBase<T> {
}
////////////////////////////////
template<typename T, typename Foo> class Bar: public Foo<pair<T, int>> {
void push(T& t) {
int value = get_val();
foo_.push(make_pair(t, v));
}
pair<T, int> pop() {
return foo_.pop();
}
Foo<pair<T, int>> foo_;
}
So basically we have different instances of class Foo, "FooDerived1", "FooDerived2" etc
We have a class Bar, which is a decorator, on top of class Foo, which should take in different any children of class Foo.
The problem is that, the decorator would initialize class FooBase's template with a modified typename. Basically change FooBase to FooBase<pair<T, int>>
Inside class Bar, I would use all of Foo's interface, and also a wrapper, around the base class function
What is the right way to do this? Because when I am trying to initialize class Bar, I am confused.
Bar<float, FooDerived1<float>> bar1;
Bar<float, FooDerived2<float>> bar2;
I am not sure how this would work and what is the right way to accomplish, what I am trying to do.
Thank you.
First, Bar needs only a single template argument. T can be deduced from an instantiation FooBase<T> via a type trait, or by using a member alias.
Then you can use SFINAE to check if that argument inherits from FooBase (which adds a second argument again):
#include <type_traits>
#include <utility>
template <typename T> struct FooBase { using type = T; };
template <typename T> struct Foo1 : FooBase<T> {};
template <typename T,typename = void> struct Bar;
template <typename T>
struct Bar< T,
std::enable_if_t<
std::is_base_of_v<
FooBase<typename T::type>,T>>
>
: FooBase<std::pair<typename T::type,int>> {};
int main() {
Bar< Foo1<int>> c;
}
Though, this would be much simpler if you drop some restrictions. If Bar<T> does not require T to inherit from FooBase and if the caller instantiates it via Bar< sometype::type > then no SFINAE is needed and Bar could be simply template <typename T> struct Bar : FooBase<std::pair<T,int>> {};. Also it is not clear what is the relevance of the derived class for Bar. In your code Bar merely uses T and FooBase. However, I hope the above will help.

Differentiate between shared_ptr and normal type on compile time

I try to create a templated class, which saves the template argument as a member variable (msg_).
Now the input of the class should allow normal types like int and shared_ptr<int>.
template <typename T>
class Foo {
public:
Foo<T>() {};
private:
T msg_;
};
My problem is if the class gets initialized with shared_ptr<int>, the shared_ptr has to get initialized:
this->msg_ = std::make_shared<T*>();
I tried to solve it like this:
Foo<T>() {
if (std::is_pointer<T>::value) {
this->msg_ = std::make_shared<T*>();
}
};
, but the problem is that is has to be solved on compile time. Otherwise I can not compile.
Do you know any patterns, which solve this issue?
Thank you! and
Best regards
Fabian
You might have specialization
template <typename T>
class Foo {
public:
Foo() {}
private:
T msg_;
};
template <typename T>
class Foo<std::shared_ptr<T>>
{
public:
Foo() : msg_(std::make_shared<T>()) {}
private:
std::shared_ptr<T> msg_;
};
or create function to initialize (with overload)
template <typename> struct tag{};
template <typename T>
T foo_default_init(tag<T>) { return {}; }
template <typename T>
std::shared_ptr<T> foo_default_init(tag<std::shared_ptr<T>>)
{
return std::make_shared<T>();
}
template <typename T>
class Foo {
public:
Foo() : msg_(foo_default_init(tag<T>{})){}
private:
T msg_;
};

Remove redundant template types

I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this
template <typename T>
class A
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like
void foo(std::vector<std::complex<float>>& result);
and not like
void foo(std::vector<std::complex<std::complex<float>>>& result);
Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice?
What is the most elegant way to solve this issue?
Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type
template <typename T>
struct getFloatType
{ using type = T; };
template <typename T>
struct getFloatType<std::complex<T>>
{ using type = T; };
and use it in A (see fT)
template <typename T>
class A
{
public:
using fT = typename getFloatType<T>::type;
void foo(std::vector<std::complex<fT>>& result)
{ }
};
You can make a partial specialization for any instantiation of std::complex, e.g.
template <typename T>
class A<std::complex<T>>
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.
To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.
class Base {
public:
void bar(...);
};
then
template <typename T>
class A : public Base {
...
};
template <typename T>
class A<std::complex<T>> : public Base {
...
};

How to use a nested typedef in a template?

I want to derive a type Test from a templated type Base which I specialise on the derived type (i.e. Base<Test>).
Inside the templated type, I want to make use of a typedef defined in the derived type (the template parameter).
However, I get this compile error:
error C2039: 'X' : is not a member of 'Test'
Here is the code snippet:
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
Is this doable, and if so, what is the fix I need to make?
(I see a couple of answers for this kind of problem but it looks like my scenario isn't fixed by prefixing typename - is it something to do with deriving from a template specialised with the derived type?)
Alternatively to the typedef, you can also declare the type as second template argument in the base class:
template <typename T, typename X>
class Base
{
protected:
void func(X x) {}
};
class Test : public Base<Test, int>
{
public:
// typedef int X;
};
You have a circularity which cannot be resolved with forward declarations. But this will work, although (I suspect) not quite so strongly defined as you wanted.
template <typename T>
class Base
{
protected:
template<typename Y>
void func(Y x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
If func were public, then you could then write
Test t;
Test::X x;
t.func(x)
which is satisfactory for any use of the Curiously Recurring Template Pattern I think of.
This works for me:
template <typename T> struct Traits;
template <typename Derived>
class Base
{
protected:
void func(typename Traits<Derived>::X x) {}
};
class Test;
template <> struct Traits<Test>
{
typedef int X;
};
class Test : public Base<Test>
{
};
I'm not sure about this behavior, maybe someone can clarify it. But as I understand by the moment you do : public Base<Test> the type name X doesn't exists (since is declared below).
If you create a wrapper class before making the inheritance the type would exists by the moment you do the inheritance and the template instantiation will work.
This compiles with VC++ 2013
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class TestWrapper
{
public:
typedef int X; //Declared, now it exists for the compiler
};
class Test
:public Base<TestWrapper> //Compiles correctly
{
};

Class template with template class friend, what's really going on here?

Let's say I'm creating a class for a binary tree, BT, and I have a class which describes an element of the tree, BE, something like
template<class T> class BE {
T *data;
BE *l, *r;
public:
...
template<class U> friend class BT;
};
template<class T> class BT {
BE<T> *root;
public:
...
private:
...
};
This appears to work; however I have questions about what's going on underneath.
I originally tried to declare the friend as
template<class T> friend class BT;
however it appears necessary to use U (or something other than T) here, why is this? Does it imply that any particular BT is friend to any particular BE class?
The IBM page on templates and friends has examples of different type of friend relationships for functions but not classes (and guessing a syntax hasn't converged on the solution yet). I would prefer to understand how to get the specifications correct for the type of friend relationship I wish to define.
template<class T> class BE{
template<class T> friend class BT;
};
Is not allowed because template parameters cannot shadow each other. Nested templates must have different template parameter names.
template<typename T>
struct foo {
template<typename U>
friend class bar;
};
This means that bar is a friend of foo regardless of bar's template arguments. bar<char>, bar<int>, bar<float>, and any other bar would be friends of foo<char>.
template<typename T>
struct foo {
friend class bar<T>;
};
This means that bar is a friend of foo when bar's template argument matches foo's. Only bar<char> would be a friend of foo<char>.
In your case, friend class bar<T>; should be sufficient.
In order to befriend another same-type struct:
#include <iostream>
template<typename T_>
struct Foo
{
// Without this next line source.value_ later would be inaccessible.
template<typename> friend struct Foo;
Foo(T_ value) : value_(value) {}
template <typename AltT>
void display(AltT &&source) const
{
std::cout << "My value is " << value_ << " and my friend's value is " << source.value_ << ".\n";
}
protected:
T_ value_;
};
int main()
{
Foo<int> foo1(5);
Foo<std::string> foo2("banana");
foo1.display(foo2);
return 0;
}
With the output as follows:
My value is 5 and my friend's value is banana.
In template<typename> friend struct Foo; you shouldn't write T after typename/class otherwise it will cause a template param shadowing error.
It's not necessary to name the parameters so you get fewer points of failure if refactoring:
template <typename _KeyT, typename _ValueT> class hash_map_iterator{
template <typename, typename, int> friend class hash_map;
...
The best way to make a template class a friend of a template class is the following:
#include <iostream>
using namespace std;
template<typename T>
class B;
template<typename T>
class A
{
friend class B<T>;
private:
int height;
public:
A()//constructor
A(T val) //overloaded constructor
};
template<typename T>
class B
{
private:
...
public:
B()//constructor
B(T val) //overloaded constructor
};
In my case this solution works correctly:
template <typename T>
class DerivedClass1 : public BaseClass1 {
template<class T> friend class DerivedClass2;
private:
int a;
};
template <typename T>
class DerivedClass2 : public BaseClass1 {
void method() { this->i;}
};
I hope it will be helpful.