Advanced C++: Copy configuration (object) in a template template class's instance - c++

I have a problem with templatized classes that I made most abstract with this example.
So for a class which has the form
template <typename T, template <typename T> class MyFunctor>
class MyMainClass
{
MyFunctor<T> myInstance;
public:
setConfigOfMyFunctor<ConfigClass>(const ConfigClass& cfg); //problem is here. How can I write this?
}
I define FunctorClass which I will use as the second template parameter in MyMainClass
template <typename T>
class FunctorClass
{
public:
ConfigClass<T> cfg;
int a;
int b;
int c;
}
where my config class is simply
template <Typename T>
class ConfigClass
{
T cfgval1;
T cfgval2;
public:
void setVals(int cfgVal1, ...);
//.....
}
If I make an object of this class
int main()
{
typedef double T;
MyMainClass<T,FunctorClass> classy;
ConfigClass<T> config;
config.setVals(1, 2, ...);
//so I'm looking for something like the following line (taken from first declaration)
classy.setConfigOfMyFunctor<ConfigClass>(config); //this is supposed to copy the object config to the FunctorClass's object in MyMainClass.
}
So in brief, I want the object config to be copied to MyMainClass<>::FunctorClass<>::cfg
Is that possible?
If you need more information on the problem, please let me know.
Thank you for any efforts.

You needn't parametrize setConfigOfMyFunctor with any type since you already know type of accepted config - ConfigClass<T>.
So you should be able to do it like that:
template <typename T, template <typename T> class MyFunctor>
class MyMainClass
{
MyFunctor<T> myInstance;
public:
template<template <typename T> class Config>
setConfigOfMyFunctor(const Config<T>& cfg) {
myInstance.cfg = cfg;
}
}
(you'll need to add keyword typename somewhere (before Config<T>, most likely) if compiler asks you to)

Related

What template<typename> template <typename> does?

Recently I stumbled upon such piece of code:
template <typename Ta> template <typename Tb>
void SomeClass<Ta>::Function() {}
There is template function, but it has strange syntax, which I don't really understand. What does it do? Is it anwhere near template<template<typename Ta>>?
I have never met such syntax, and I am confused.
Sometimes all it needs is a complete example:
template <typename Ta>
struct SomeClass {
template <typename Tb>
void Function();
};
template <typename Ta> template <typename Tb>
void SomeClass<Ta>::Function() {}
int main() {
SomeClass<int> sc;
sc.Function<double>();
}
It is a definition of a method template of a class template.
Sometimes You need compatibility with compatible objects while writing templates. For example int and double are compatible with each other. But if you have a template class objects lets say Something<int> and Something<double> and you try to assign them it will not work. You do this especially while writing copy or move assignment operators or constructors. Let suppose we have an a class template Something.
template <typename T>
class Something {
public:
Something();
Something(const Something& obj) : data(obj.data)
{
};
private:
T data;
};
int main(){
Something<int> number;
Something<double> double_number;
Something<double> newObj(number);
}
if you try to do this, it will not compile.
To make it compile you make template of your copy constructor as in this case. To make it compile you have to something like this.
template <typename T>
class Something {
public:
Something();
template<typename E>
Something(const Something<E>& obj);
T get_data() const{
return data;
}
private:
T data;
};
template<typename T>
template <typename E>
Something<T>::Something(const Something<E>& src): data(src.get_data()){
}
int main(){
Something<int> number;
Something<double> double_number;
Something<double> newObj(number);
}
Note that we are calling the public method to assign data to this object because Something<int> and Something<double> both are of different types.

Specialise only parts of template class while keeping the rest generic

Assuming the following class:
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
}
How can I add another function to a specialisation of the class while not rewriting all possibly 100 functions that are already templated?
template<>
class Test<int> {
public:
void do_something_else();
}
...
int main() {
auto x = Test<int>();
x.do_something5(); // should be still valid, would call
// Test<T>::do_something5() with T being int
x.do_something_else(); // valid because declared in specialisation
...
}
Right now, if the Test<int> specialisation is left as in the example above, it would only contain do_something_else(), without do_something1...100().
Solution
Based on the accepted answer, using the given example, I did the following:
namespace parent {
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100();
}
}
template <typename T>
class Test : public parent::Test<T> {
using parent::Test<T>::Test; // inherit constructors
}
template <>
class Test<int> : public parent::Test<int> {
using parent::Test<int>::Test;
public:
void do_something_else();
}
You can create a common base class, and make both the primary template and specialization deriving from it.
Or you can make do_something_else function template and only works with int (then don't need using specialization).
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
template <typename X = T>
std::enable_if_t<std::is_same_v<X, int> && std::is_same_v<X, T>> do_something_else();
};
Or since C++20 we can use Constraints as #aschepler suggested.
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
void do_something_else() requires std::is_same_v<T, int>;
};

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 {
...
};

Using template class with the incomplete type void

I have the following template class :
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
T attribute
// Other attributes.
};
Instantiating an object of type myClass<void> does not work, because of void attribute.
Can you give me some hints to be able to use objects of type myClass<void> without specializing the whole class. Since it has many member functions that rely on the type T, specializing it will lead to code duplication.
Create a templated base class containing attribute, specialize it for void and inherit from it:
namespace detail //Warn end user that he should not use stuff from here
{
template <typename T>
struct myClass_base
{
T attribute;
};
template <>
struct myClass_base<void>
{}; //No attribute at all
}
template <typename T>
class myClass: private detail::myClass_base<T>
{
//rest of definition
};
This would make myClass lack attribute field when instantiating it with type void
You can defer the whole problem by using a custom type and specializing that:
template<typename T>
struct my_type_t
{
using type = T;
};
template<>
struct my_type_t<void>
{};
template<typename T>
using my_type = typename my_type_t<T>::type;
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
my_type<T> attribute
// Other attributes.
};
Then at least you don't have to duplicate the whole rest of the class again.
But it probably does not make that much sense, as you surely want to use the type somewhere. So you would have to specialize that places further.

How can a class declare all of its variadic template parameters friends?

If I have a class which takes variadic pack of template arguments how can I declare them all to be friends?
Here is what I would like to do in pseudo-code form:
template<typename... Ts>
class AbstractMyClass {
int privateInt;
friend Ts...;
};
class OtherClass;
using MyClass = AbstractMyClass<OtherClass>;
class OtherClass {
public:
void foo(MyClass &c){
c.privateInt = 42;
}
};
This can only be done using "compile time recursion", much like tuples. The gist is (I am on a small laptop right now and by no means able to comfortably type):
template<class .... THINGS> class object;
template<class T> class object {
friend T;
};
template<class T,class ... THINGS>
class object: public object<THINGS> {
friend T;
};
If C++ doesn't like that, try template<> class object<> {}; as the one that ends the recursion (I terminate it with an object in 1 template paramater)
(Thanks to Dietmar Kuhl for formatting)