C++ Template Specialization with non-generic arguments - c++

i have a quiestion regarding template specializations when i have multiple arguments and some of them are non generic
I have a class called Polinom(polynomian) which is basically an array of T objects with a size declared in the template definition(as an int). I also have a class called Complex. Now what I want is to create a template specialization so that I will call different functions(overloaded operator functions) when I have a polinomial with Complex as T. My question is how can I do this, I am getting an error "type name not allowed, stepen undefined" when trying to create the specialization, if someone could clear up what is going on here that would be great.
#pragma once
#include <iostream>
#include <cmath>
using namespace std;
template<class T, int stepen>
class Polinom
{
private:
T koeficijenti[stepen];
public:
Polinom() {};
~Polinom() {};
void ucitajKoef();
T vrednost(T x);
};
template<>
class Polinom<Complex, int stepen> //error type name not allowed
{
};
template<class T, int stepen>
T Polinom<T, stepen>::vrednost(T x)
{
T suma = koeficijenti[1] * (T)pow(x, stepen);
for (int i = 1; i < stepen; i++)
{
suma += koeficijenti[i] * pow(x, stepen - i);
}
return suma;
}
template<class T, int stepen>
void Polinom<T, stepen>::ucitajKoef()
{
T uneseniKoef;
for (int i = 0; i < stepen; i++)
{
cout << "Unesite koeficijent" << endl;
cin >> uneseniKoef;
koeficijenti[i] = uneseniKoef;
}
}
P.S. Is there a workaround to having to rewrite all the other functions of the class since I am only specializing so I can overload the function vrednost(value)

The specialization should look like:
#include <iostream>
template <typename T, int N>
struct Array {
T var[N];
T sum() {
T res{};
for (T v:var) {
res += v;
}
return res;
}
};
struct Complex {};
template <int N>
struct Array<Complex, N> {
Complex var[N];
Complex sum() {
std::cout <<"Complex sum called\n";
return {};
}
};
int main()
{
Array<Complex,5> array;
array.sum();
}
Note that this is a minimal (I think), complete, and verifiable example. You will get better answers if you take the time to create something similar when you ask a question.
To answer your question: I know of no way to simply specialize just one function in a template - which is why you get complex things like the CRTP and individual functions which are invoked from the members (and which can be individually specialized).

Related

Using C++20 concept/requires for function partial specialization

I'm learning C++20 concept/requires. I would like to implement a function for getting the sum of an integer list with template meta programming:
sum<IntList<1, 2, 3>>();
As it's known that C++ standards don't allow function partial specialization, I would like to use C++20 concept/requires to the similar stuff as function partial specialization.
Here is my code:
#include <iostream>
template<int...N>
class IntList;
template<int...N>
concept IsIntList = IntList<N...>{};
template<typename T>
int sum() {
return 0;
}
template<int...N>
requires IsIntList<N...>
int sum() {
return (N + ...);
}
int main() {
std::cout << sum<IntList<1, 2>>() << std::endl;
return 0;
}
But it could not produce what I want. Put my code in C++ Insights. The first sum is instantiated, instead of the second sum.
Here is the result of C++Insights:
#include <iostream>
template<int...N>
class IntList;
template<int...N>
concept IsIntList = IntList<N...>{};
template<typename T>
int sum() {
return 0;
}
/* First instantiated from: insights.cpp:21 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
int sum<IntList<1, 2> >()
{
return 0;
}
#endif
template<int...N>
requires IsIntList<N...>
int sum() {
return (N + ...);
}
int main()
{
std::cout.operator<<(sum<IntList<1, 2> >()).operator<<(std::endl);
return 0;
}
What's the correct way to solve this problem? Thanks!
The central problem you're encountering is that you have a type template parameter whose type you want to be constrained to being some specialization of some template. That's not a thing you can do with a requires clause. At least, not easily.
It's best to avoid this problem. You're only encountering it because you insist that sum's template parameter must be some specialization of IntList instead of the integers themselves directly. The best way to handle this is by ditching this assumption:
template<int... Ints>
constexpr int sum(IntList<Ints...>)
{ return (0 + ... + Ints); }
You then call this function as so: sum(IntList<1, 2>{}). Note that IntList needs to have a constexpr default constructor.
Your definition of the concept of IsIntList is wrong, it only evaluates the value of IntList<N...>{}, and since IntList is not a bool type, IsIntList always return false.
You should use template partial specialization to define the IsIntList.
template<int...N>
class IntList;
template<class T>
inline constexpr bool IsIntList = false;
template<int...N>
inline constexpr bool IsIntList<IntList<N...>> = true;
For a specialized version of the sum, just constrain IsIntList<T> to be true, then you can extract the value of the IntList with the help of a tag class and template lambda to calculate the sum.
template<class>
struct tag{};
template<class T>
requires IsIntList<T>
int sum() {
return []<int...N>(tag<IntList<N...>>)
{ return (N + ... + 0); }(tag<T>{});
}
Demo.

Return different types with different template parameter value (but same type)

What I want to do is to define 3 functions like these:
template<int t = 0> int test() { return 8; }
template<int t = 1> float test() { return 8.8; }
template<int t = 2> std::string test() { return "8.9"; }
int main()
{
int a = test<0>();
float b = test<1>();
std::string c = test<2>();
return 0;
}
They use the same type of template parameter but return different types.
I believe there must be some way to do that (like std::get<>() does it), but I can not find how to do it.
It looks to me like you are after function template specialization. Needing to provide a different implementation for each of the calls fits the bill. There is however one caveat, and it's that a specialization may not alter the signature of the primary template being specialized, only the implementation. This means we cannot do e.g.
template<int t> int test(); // Primary
template<> int test<0>() { return 8; } // OK, signature matches
template<> float test<1>() { return 8.8; } // ERROR
But we are not toasted yet. The signature of the specialization has to match the one that primary will get for a specific argument. So if we make the return type dependent on the template parameter, and resolve to the correct type, we could define our specialization just fine.
template<int t> auto test() -> /* Magic involving t that resolves to int, float, string */;
template<> int test<0>() { return 8; }
template<> float test<1>() { return 8.8; }
template<> std::string test<2>() { return "8.9"; }
Does something like that exist? Yes, and you hinted at it. We can use std::tuple. It has a std::tuple_element utility that can map an integer to one of a type sequence (the tuple's elements). With a little helper, we can construct our code to work the way you wish:
using types = std::tuple<int, float, std::string>;
template<int t> auto test() -> std::tuple_element_t<t, types>;
template<> int test<0>() { return 8; }
template<> float test<1>() { return 8.8; }
template<> std::string test<2>() { return "8.9"; }
Now every specialization matches the signature the primary would end up with. And so we get an approval from our compiler.
See it live
The #StoryTeller and #formerlyknownas_463035818 have provided a well-explained template specialization way of doing it. Alternatively, one can combine the three functions to one single function using if-constexpr and with a decltype(auto) return in c++17.
#include <iostream>
#include <string>
#include <cstring>
using namespace std::literals;
template<int t>
constexpr decltype(auto) test() noexcept
{
if constexpr (t == 0) return 8;
else if constexpr (t == 1) return 8.8f;
else if constexpr (t == 2) return "8.9"s;
}
(See live online)
You declared the same template 3 times, while you actually want specialisations. As far as I know you cannot specialize on return type directly (*). However, there is nothing that cannot be solved with an additional layer of indirection. You can do something along the line of:
#include <string>
template <int> struct return_type_tag {};
template <> struct return_type_tag<0> { using type = int; };
template <> struct return_type_tag<1> { using type = float; };
template <> struct return_type_tag<2> { using type = std::string; };
template <int x> typename return_type_tag<x>::type test();
template<> int test<0>() { return 8; }
template<> float test<1>() { return 8.8; }
template<> std::string test<2>() { return "8.9"; }
int main()
{
int a = test<0>();
float b = test<1>();
std::string c = test<2>();
return 0;
}
(*) actually you can, with a small trick, see this answer. The only benefit of my approach is that it already worked pre-c++11.

Using a templated function as template parameter

I'm writing a class with a function that is repeatedly called and decided to implement this as giving the function as template parameter.
As a concrete example of what I'm talking about, consider the following class:
#include <array>
template<double (*func)(std::array<double,3>)>
class MyClass
{
public:
MyClass()
{
std::array<double,3> v {{0.1,0.2,0.1}};
func(v);
}
};
which can then be instantiated with a function, as for example:
double func(std::array<double,3> x)
{
return x[0]*x[0]+x[1];
}
int main()
{
MyClass<func> entity;
}
However, I need the function to be callable with different types (the operations in the function are of course applicable to all of them), that is I want to have this function templated, as in:
template<typename scalartype, typename vectype>
scalartype func1(vectype x)
{
scalartype res = x[0]*x[0]+x[1];
return res;
}
I can still use this as template parameter, but the function parameter and return type are then fixed in the class. So how can I have the function as templated function available in the class? Such that I can, for example, call it with an std::vector of four integers and have an integer returned.
I tried using template template parameters, but I can't even figure out how to use two template parameters with them (as they only seem to allow the template ... syntax). I'm sorry if this is formulated unclearly, I am still a newcomer.
You can put your template function in a class, and then pass in that class to MyClass.
#include <iostream>
#include <vector>
#include <array>
struct templateHolder {
template <typename vectype, typename scalartype = typename vectype::value_type>
static scalartype func(vectype x) {
return x[0] + x[1];
}
};
template<typename T>
class MyClass
{
public:
MyClass()
{
std::vector<int> vec {1,2};
std::cout << T::func(vec) << std::endl;
std::array<double, 2> arr {0.5, 3.33};
std::cout << T::func(arr) << std::endl;
}
};
int main() {
MyClass<templateHolder> foo;
return 0;
}
I chose to deduce scalartype from vectype. Not necessarily what you want but it could be an option depending on your use-case.

Managing a collection of vectors of templated derived types

The X: What I want to do:
I have the types: BaseType and DerivedType<int k> (see code below), and I need to handle a collection of K vectors of the derived types std::vector<DerivedType<k>>, k = 1...K. I'd like to access the objects in these vectors, and perform an operation on them that depends on k. K is a compile time constant. The problem is illustrated in the implementation:
The types are defined as:
#include <iostream>
#include <algorithm>
struct BaseType { // Interface of the DerivedTypes
virtual void print(){std::cout << "BaseType!" << std::endl; }
};
template< int k >
struct DerivedType : public BaseType {
static const int k_ = k;
// ... function calls templated on k ...
void print(){std::cout << "DerivedType: " << k_ << std::endl;}
};
template< int k >
void doSomething ( DerivedType<k>& object ) { object.print(); }
And what I want to do is:
int main() {
// My collection of vectors of the derived types:
std::vector<DerivedType<0>> derType0(2);
std::vector<DerivedType<1>> derType1(1);
std::vector<DerivedType<2>> derType2(3);
// ... should go to K: std::vector<DerivedType<K>> derTypeK;
// Iterate over the derived objects applying a k-dependent templated function:
std::for_each(begin(derType0),end(derType0),[](DerivedType<0>& object){
doSomething<0>(object);
});
std::for_each(begin(derType1),end(derType1),[](DerivedType<1>& object){
doSomething<1>(object);
});
std::for_each(begin(derType2),end(derType2),[](DerivedType<2>& object){
doSomething<2>(object);
});
return 0;
}
I want to avoid repeating code, such that I only have to change K, which is a compile time constant of O(10). Ideally, I would have something "more like" this:
// Pseudocode: do not try to compile this
create_derived_objects(DerivedType,K)
= std::vector< std::vector<DerivedType<k>>* > my_K_derived_types;
for each vector<DerivedType<k>>* derivedTypes in my my_K_derived_types
for each object in (*derivedTypes)
doSomething<k> on object of type derivedType<k>
// I could also restrict doSomething<k> to the base interface
Each vector of derived types contains O(10^6) to O(10^9) objects. The inner-most loops are the most time consuming part of my application making dynamic_cast only an option for the outer-most loop.
The Y: what I have tryed without succes.
I am at the moment studying the Abrahams C++ Template Metaprogramming book to see if I could use boost::mpl. I am also doing the tutorials on boost::fusion to see if I could use it too. However, the learning curve of these libraries is rather large, so I wanted to ask first before I invest a week in something when a better and simpler solution is available.
My first try was to wrapp my vectors std::vector<DerivedType<k>> such that I can create a vector<WrappedDerivedTypes*>, and access each of the single vectors separately within a for_each loop. However, in the loop I have a series of if(dynamic_cast<std::vector<DerivedType<0>>>(WrappedVector) != 0 ){ do for_each loop for the derived objects } else if( dynamic_cast...) { do...} ... that I wasn't able to eliminate.
What about a recursive solution based on a generic linked list of vectors, a strategy pattern and a thing that applies strategies recursively through the linked list? (note: see the improved version at the end):
#include <iostream>
#include <vector>
template <int j>
class holder {
public:
const static int k = j;
};
template <int j>
class strategy {
public:
void operator()(holder<j> t)
{
std::cout << "Strategy " << t.k << std::endl;
}
};
template <int k>
class lin_vector {
private:
std::vector<holder<k>> vec;
lin_vector<k-1> pred;
public:
lin_vector(const lin_vector<k-1> &pred, std::vector<holder<k>> vec)
: vec(vec), pred(pred) { }
std::vector<holder<k>> get_vec() { return vec; }
lin_vector<k-1> &get_pred() { return pred; }
};
template <>
class lin_vector<0> {
public:
lin_vector() { }
};
template <int k, template <int> class strategy>
class apply_strategy {
public:
void operator()(lin_vector<k> lin);
};
template <int k, template <int> class strategy>
void apply_strategy<k, strategy>::operator()(lin_vector<k> lin)
{
apply_strategy<k-1, strategy>()(lin.get_pred());
for (auto i : lin.get_vec())
strategy<k>()(i);
}
template <template <int> class strategy>
class apply_strategy<0, strategy>
{
public:
void operator()(lin_vector<0> lin) { /* does nothing */ }
};
template <int k>
lin_vector<k> build_lin()
{
return lin_vector<k>(build_lin<k-1>(), {holder<k>()});
}
template <>
lin_vector<0> build_lin()
{
return lin_vector<0>();
}
int main(void)
{
apply_strategy<5, strategy>()(build_lin<5>());
}
Compile it with a C++11 compiler.
Most probably you'll find unsatisfactory the fact that building a lin_vector requires a lot of copying, but you can specialize the structure to suit your needs (perhaps substituting the pred with a pointer or embedding the creation strategy straight into the linked list).
EDIT: here there is an improved version which avoids a lot of copying and handles list building and processing in a more coherent and uniform way:
#include <iostream>
#include <vector>
template <int j>
class holder {
public:
const static int k = j;
};
template <int k>
class lin_vector {
private:
std::vector<holder<k>> vec;
lin_vector<k-1> pred;
public:
std::vector<holder<k>> &get_vec() { return vec; }
lin_vector<k-1> &get_pred() { return pred; }
};
template <>
class lin_vector<0> {
public:
lin_vector() { }
};
template <int k, template <int> class strategy>
class apply_strategy {
public:
void operator()(lin_vector<k> &lin);
};
template <int k, template <int> class strategy>
void apply_strategy<k, strategy>::operator()(lin_vector<k> &lin)
{
apply_strategy<k-1, strategy>()(lin.get_pred());
strategy<k>()(lin.get_vec());
}
template <template <int> class strategy>
class apply_strategy<0, strategy>
{
public:
void operator()(lin_vector<0> &lin) { /* does nothing */ }
};
template <int j>
class strategy {
public:
void operator()(std::vector<holder<j>> &t)
{
std::cout << "Strategy " << j << ", elements: ";
for (auto v : t)
std::cout << v.k << " ";
std::cout << std::endl;
}
};
template <int j>
class build_strategy {
public:
void operator()(std::vector<holder<j>> &t)
{
for (unsigned int i = 0; i < j; i++)
t.push_back(holder<j>());
}
};
int main(void)
{
const int K = 5;
lin_vector<K> list;
apply_strategy<K, build_strategy>()(list);
apply_strategy<K, strategy>()(list);
}
A solution free of virtual dispatch is possible, though it's probably overkill.
The first thing you need is a function template doSomething<K>() that you specialise on each derived type:
template <int K>
void doSomething(vector<DerivedType<K> >& x);
template <>
void doSomething<1>(vector<DerivedType<1> >& x) { ... }
template <>
void doSomething<2>(vector<DerivedType<2> >& x) { ... } // etc.
You could then build a strongly-typed collection of vectors using a recursively defined struct template:
template <int K>
struct vov {
vov<K - 1> prev;
vector<DerivedType<K> > v;
};
template <>
struct vov<1> {
vector<DerivedType<1> > v;
};
Finally, you can write a recursive function template to process this structure:
template <int K>
void process(vov<K>& x) {
doSomething(x.v); // Type inference will find the right doSomething()
process(x.prev); // Here too
}
template <>
void process<1>(vov<1>& x) {
doSomething(x.v);
}
Now the main code will look like:
vov<42> foo;
process(foo);
Because the process() function call performs iteration through the use of recursion, it will probably use K stack frames unnecessarily; however it is tail recursion, which modern optimising C++ compilers can usually convert into plain iteration with no stack wastage. Using tail recursion forces us to process the vectors in "reverse" order, so that the DerivedType<1> vector is processed last, but if necessary this could be fixed with a slightly more elaborate template using 2 int template parameters (one will "count up" towards the other, instead of a single int parameter that "counts down" towards 1).
Observe that there is no benefit gained by deriving each DerivedType<k> from BaseType in this solution -- you may as well forget about BaseType altogether, unless you need it for a different reason.
There may well be MPL primitives that simplify some of these processes -- if anyone knows them, please feel free to edit.

How to create and use a non type template in c++ and where would it be used

i am trying to learn templates in c++. Can someone please explain why sq() works and add() does not? How can add() be fixed? What is use of non type templates?
template <typename T>
inline T sq (const T& x)
{
return x*x;
}
template <int*>
inline int add(int* x)
{
return (*x)*2;
}
int main() {
int x = 2;
cout<<"Square(2): "<<sq(2)<<" Add(2): "<<add(&x)<<endl;
return 0;
}
Even after modifying the above example as below, it would still Not work
template <typename T>
inline T sq (const T& x)
{
return x*x;
}
template <int>
inline int add(int x)
{
return x+x;
}
int main() {
cout<<"Square(2): "<<sq(2)<<" Add(2): "<<add(2)<<endl;
return 0;
}
I'm not quite sure what you're asking, but you could use a non-type template parameter to, for example, define a function template that adds any compile-time constant to its argument:
template <int N>
inline int add(int x)
{
return x + N;
}
int main()
{
std::cout << add<3>(2) << std::endl; // prints 5
std::cout << add<4>(2) << std::endl; // prints 6
}
To answer your specific question about why sq(2) compiles but add(&x) doesn't: type parameters of function templates can be deduced from the function arguments. So sq(2) is equivalent to sq<int>(2). Non-type parameters can't be deduced, so you have to provide one. In the case of a pointer parameter, the argument must be a pointer to a variable with external linkage, so the following should compile:
int global;
int main() {
int local = 2;
std::cout << add<&global>(&local) << std::endl;
}
The classical example of using a non-type template parameter for a
function template would be something like:
template <typename T, size_t N>
T*
end( T (&array)[N] )
{
return array + N;
}
In this case, if you write something like:
int a[] = { 1, 2, 3, 4 };
int* endPtr = end(a);
, the compiler can deduce the length of the array for you.
Your add function doesn't use any template-related features. It would work fine as a non-template function. I can't make out what you're really trying to do so unfortunately I can't even guess at a fix for your real problem.
EDIT: If from your title I infer you want to know about non-type template parameters, what about a totally incomplete array example:
template <typename T, int length>
struct Array
{
T array_data_[length];
};
As it was said, what you are trying to do is some how pointless, the only case when you might want to provide the exact parameter type in templates is for template functions overloading. for instance when you want to make some function work in different manner for some special type this is called template specialization. For more details you might want to visit
:
Function template specialization format
The point of templates is that so you dont have to define a specific datatype in the function or class.
Look at T add (const T& x) . There is no datatype in here, just a big T . That's due to that templates can assume the identity of any datatype, int, double, char or whatever you throw at it.
#include <iostream>
using namespace std;
template <typename T>
inline T sq (const T& x)
{
return x*x;
}
template <typename T>
inline T add (const T& x)
{
return x+x;
}
template <typename T>
inline T divide (const T& x, const T& y)
{
return x/y;
}
int main()
{
int x = 3;
cout<<"int \n";
cout<<"Square(3) : "<<sq(x)<<" \n";
cout<<"Add(3) : "<<add(x)<<" \n";
double y=3.00;
cout<<"\ndouble \n";
cout<<"Square(3) : "<<sq(y)<<" \n";
cout<<"Add(3) : "<<add(y)<<" \n";
double v=3.00;
double w=2.00;
cout<<"\ndouble \n";
cout<<"Square(3) : "<<sq(v)<<" \n";
cout<<"Add(3) : "<<add(v)<<" \n";
cout<<"divide(3/2) : "<<divide(v,w)<<" \n";
cout<<"\n \n";
return 0;
}