Variadic template class expansion - c++

I have the following template class where I want to cycle through the template types and do something for each type. This is a simplified example.
template<class... T>
class Handler
{
private:
template<class A>
void Do1_(int a, int b)
{
A obj{};
obj.Process(a, b);
}
template<class A, class... B>
void Do_(int a, int b)
{
Do1_<A>(a, b);
Do_<B...>(a, b);
}
public:
void Do(int a, int b)
{
Do_<T...>(a, b);
}
};
struct Foo1 {
void Process(int a, int b) {}
};
struct Foo2 {
void Process(int a, int b) {}
};
class Bar : public Handler<Foo1, Foo2> {};
But the expansion for Do_<B...> gives me trouble, I get compilation error about "could not deduce template argument for 'A'", when compiling Do_<B...>. What should be the correct expansion be here in order to make it compile, if possible.

You are over-complicating matters. This should do (no pun intended):
template<class... T>
class Handler
{
public:
void Do(int a, int b) {
int dummy[] = {(T{}.Process(a, b), 0)...};
}
};
Demo

Related

Normalize construction of objects that contain compile-time *or* runtime values

Lets say I have two classes
template <int A_, int B_>
class One {
public:
static constexpr auto A = A_;
static constexpr auto B = B_;
const int C;
One(int C) : C(C) {}
};
class Two {
public:
const int A;
const int B;
const int C;
Two(int A, int B, int C) : A(A), B(B), C(C) {}
};
The only difference being that class One takes the A and B parameters at compile time, while Two takes the parameters at runtime. There exist multiple operations on these essentially equivalent types, so they can be written generically:
template <typename T>
auto min(const T& a, const T& b) {
if (a.C < b.C) {
return T(a.A+b.A, a.B+b.B, a.C);
} else {
return T(a.A+b.A, a.B+b.B, b.C);
}
}
The issue with the above is the construction of the output object. The two types One and Two can be used in the same way to access the A, B, and C members, getting the types of them, etc. However, because there is a disparity in the construction of the objects (feeding function arguments vs feeding template arguments), if the operation requires the creation of a new object, it cannot be written generically.
I have tried non-type template argument deduction, but that is not currently possible. Is there any way around this? Or am I doomed to copying code?
You might create your constant int class similar to std::integral_constant but extended with needed function, something like:
template <int N> struct int_c
{
static constexpr int value = N;
};
template <int N1, int N2>
constexpr int_c<N1 + N2> operator + (int_c<N1>, int_c<N2>) { return {}; }
template <int N>
std::ostream& operator << (std::ostream& os, int_c<N>) { return os << N; }
Then change your class to have near interface, especially for constructor add factory method:
template <int A_, int B_>
class One {
public:
static constexpr int_c<A_> A{};
static constexpr int_c<B_> B{};
const int C;
One(int C) : C(C) {}
template <typename IA, typename IB>
static One<IA::value, IB::value> Create(IA, IB, int C) { return {C}; }
};
class Two {
public:
const int A;
const int B;
const int C;
Two(int A, int B, int C) : A(A), B(B), C(C) {}
static Two Create(int A, int B, int C) { return {A, B, C}; }
};
Then your common code may look like:
template <typename T1, typename T2>
auto min(const T1& a, const T2& b) {
if (a.C < b.C) {
return T1::Create(a.A + b.A, a.B + b.B, a.C);
} else {
return T1::Create(a.A + b.A, a.B + b.B, b.C);
}
}
Demo

How can I build a function concept with a particular signature?

I'm writing some generic software using concepts and I want to check if a particular function symbol name exists with a signature of (void)(int,int) on a struct. To do this I've I'm thinking of approaching this problem through template specialization but I'm sort of lost.
What I want is something to work and through compile time errors if the concept is not satisfied like so:
struct TypeA {
// Passes concept
void process (int a ,int b) const {};
};
struct TypeB {
// Does not pass concept
void process (float a) const {};
};
struct TestConcepts {
/* concept code here */
TestConcepts(T t) {
process_concept(t.process);
};
};
int main(void) {
// Should pass
TestConcept(TypeA{});
// Should throw error
TestConcept(TypeB{});
return 0;
}
I'm having a hard time filling in the blanks but this is what I have so far:
struct TestConcepts {
/* concept code here */
struct process_concept {
process_concept((V*)(IA,IB)){
if (is_integral<IA>::value && is_integral<IB>::value && is_same<V, void>) {
return;
}
static_assert(false, "You must provide function called process of type (void)(int,int)");
};
};
TestConcepts(T t) {
process_concept(&t.process);
};
};
Unfortunately this doesn't work. How can I get this function signature correct?
How about using a function that returns a declared function pointer?
struct TypeA {
// Passes concept
void process (int a ,int b) const {};
};
struct TypeB {
// Does not pass concept
void process (float a) const {};
};
template<typename T>
auto TestConcepts(T) -> void(T::*)(int, int) const
{
return &T::process;
}
int main(void) {
// Should pass
TestConcepts(TypeA{});
// Should throw error
TestConcepts(TypeB{});
return 0;
}
Output:
Error(s):
source_file.cpp: In instantiation of ‘void (T::* TestConcepts(T))(int, int) const [with T = TypeB]’:
source_file.cpp:26:23: required from here
source_file.cpp:19:16: error: cannot convert ‘void (TypeB::*)(float) const’ to ‘void (TypeB::*)(int, int) const’ in return
return &T::process;
^
EDIT: more options
If you want to include void process(long int a, long int b) const; or void process(int a, int b, int c=0) const;, like aschepler is suggesting, you can use type traits.
struct TypeA {
// Passes concept
void process(int a, int b) const {};
};
struct TypeB {
// Does not pass concept
void process(float a) const {};
};
struct TypeC {
// Passes concept
void process(long int a, long int b) const {};
};
struct TypeD {
// Passes concept
void process(int a, int b, int c = 0) const {};
};
struct TypeE {
// Does not pass concept
void process(int a, int b, int c) const {};
};
#include <type_traits>
template<typename T, typename A1, typename A2, typename... An>
typename std::enable_if<
std::is_integral<A1>::value &&
std::is_integral<A2>::value
>::type
TestProcess(const T& t, void(T::*)(A1, A2, An...) const) {
t.process(1, 2);
};
template<typename T>
void TestConcepts(const T& t)
{
TestProcess(t, &T::process);
}
int main(void) {
// Passes
TestConcepts(TypeA{});
// Throws compilation error
TestConcepts(TypeB{});
// Passes
TestConcepts(TypeC{});
// Passes
TestConcepts(TypeD{});
// Throws compilation error
TestConcepts(TypeE{});
return 0;
}

Template as parameter in class

I have header file and in my header file I make a template and I want to use the template just on one function and not force all other functions. Is it possible to get the type before the function like i did in main?
This is an example:
TestTemp.h
// TestTemp.h
#ifndef _TESTTEMP_H_
#define _TESTTEMP_H_
template<class T>
class TestTemp
{
public:
TestTemp();
void SetValue( int obj_i );
int Getalue();
void sum(T b, T a);
private:
int m_Obj;
};
#include "TestTemp.cpp"
#endif
TestTemp.cpp
//TestTemp.cpp
include<TestTemp.h>
TestTemp::TestTemp()
{
}
void TestTemp::SetValue( int obj_i )
{
m_Obj = obj_i ;
}
int TestTemp::GetValue()
{
return m_Obj ;
}
template<class T>
void TestTemp<T>::sum(T b, T a)
{
T c;
c = b + a;
}
main.cpp
//main.cpp
include<TestTemp.h>
void main()
{
TestTemp t;
t.sum<int>(3,4);
}
Have any ideas?
Your TestTemp is a template class already, no need to make sum template function.
TestTemp<int> t;
t.sum(3, 4);
If you really want to make sum function a template function of TestTemp:
template<class T>
class TestTemp
{
public:
//....
template<typename U>
void sum(U b, U a);
private:
int m_Obj;
};
To implement it outside template class:
template<class T>
template<typename U>
void TestTemp<T>::sum(U b, U a)
{
T c;
c = b + a;
}
int main()
{
TestTemp<int> t;
t.sum<int>(3, 4);
}
However, I feel you just need a free template function
template<typename T>
T sum(T a, T b)
{ return a + b; }
// TestTemp.h
#ifndef _TEST_TEMP_H_
#define _TEST_TEMP_H_
class TestTemp
{
public:
TestTemp();
void SetValue( int obj_i );
int Getalue();
template<class T>
void sum(T b, T a);
private:
int m_Obj;
};
TestTemp::TestTemp() {}
void TestTemp::SetValue( int obj_i )
{
m_Obj = obj_i ;
}
int TestTemp::Getalue()
{
return m_Obj ;
}
template<class T>
void TestTemp::sum(T b, T a)
{
T c;
c = b + a;
}
#endif
//main.cpp
#include <TestTemp.h>
int main()
{
TestTemp t;
t.sum<int>(3,4);
return 0;
}
What you need is a normal class which has a template member function.
It's not a god idea to include an cpp file in header file. For template functions, just put it in header file.
You should take a look here. There are many examples.
I think it should work as you expect it if you just remove
template<class T>
from the
#ifndef _TESTTEMP_H_
#define _TESTTEMP_H_
--> template<class T> <--
class TestTemp
block. You don't have to define the whole class as templated when you just want a method to have template parameters.
You just need to define TestTemp as normal class of which "sum" is a template function. Then in your function "main" (i.e. the caller), the template argument will be deduced from the function arguments.
class TestTemp
{
public:
TestTemp();
void SetValue(int obj_i);
int Getalue();
template<class T>
void sum(T b, T a);
private:
int m_Obj;
};
TestTemp::TestTemp() {}
void TestTemp::SetValue(int obj_i)
{
m_Obj = obj_i;
}
int TestTemp::Getalue()
{
return m_Obj;
}
template<class T>
void TestTemp::sum(T b, T a)
{
T c;
c = b + a;
}
//main.cpp
int main()
{
TestTemp t;
t.sum(3, 4);
return 0;
}

Depending on a class template parameter, define or not define a function in the class

Suppose we have a class:
template <class Type>
class A
{
public:
void function1(float a, Type b);
void function1(float a, float b);
};
Now instantiate the class like this:
A<int> a;
It's fine, this class will have 2 overloaded functions with these parameters: (float a, int b); (float a, float b);
But when you instantiate the class like this:
A<float> a;
You get compile error:
member function redeclared.
So, depending on the type of Type, I wan't (or don't want) the compiler to define a function, something like this:
template <class Type>
class A
{
public:
void function1(float a, Type b);
#if Type != float
void function1(float a, float b);
#endif
};
But, of course, the syntax above doesn't work. Is it possible to perform such a task in C++? If possible, please provide an example.
You can use some C++11 std::enable_if :
template <class Type>
class A
{
public:
template<typename t = Type,
typename std::enable_if<!std::is_same<t, float>::value, int>::type = 0>
void function1(float a, Type b) {
}
void function1(float a, float b) {
}
};
You could use template specialization:
template <class Type>
class A {
public:
void function1(float a, Type b) {
}
void function1(float a, float b) {
}
};
template <>
class A<float> {
public:
void function1(float a, float b) {
}
};
// ...
A<int> a_int;
a_int.function1(23.4f, 1);
a_int.function1(23.4f, 56.7f);
A<float> a_float;
a_float.function1(23.4f, 56.7f);
--- EDIT ---
If you have a large number of common functions, you could do something like this:
class AImp {
public:
void function1(float a, float b) {
}
void function1(float a, double b) {
}
void function1(float a, const std::string& b) {
}
// Other functions...
};
template <class Type>
class A : public AImp {
public:
void function1(float a, Type b) {
}
using AImp::function1;
};
template <>
class A<float> : public AImp {
};
// ...
A<int> a_int;
a_int.function1(23.4f, 1);
a_int.function1(23.4f, 56.7f);
a_int.function1(23.4f, 56.7);
a_int.function1(23.4f, "bar");
A<float> a_float;
a_float.function1(23.4f, 56.7f);
a_float.function1(23.4f, 56.7);
a_float.function1(23.4f, "bar");
Use SFINAE:
#include <iostream>
#include <type_traits>
template <typename Type>
struct Foo {
template <typename T = Type>
void function1(float a, float b, typename std::enable_if<!std::is_same<T, float>::value>::type *c = 0) {
std::cout << "float\n";
}
void function1(float a, Type b) {
std::cout << "type\n";
}
};
int main() {
Foo<float> f;
f.function1(1, 1);
f.function1(1.0f,1.0f);
Foo<int> g;
g.function1(1,1);
g.function1(1.0f,1.0f);
g.function1(1.0,1.0); // warning!
}
Output:
type
type
type
float
type
You'll need C++11 mode, to allow the default template parameter in a function template. And also to get enable_if and is_same, although you could get enable_if from Boost instead.
The "warning!" is because with your original code g.function1(1.0,1.0); was ambiguous. Now the the non-template overload is preferred. You can make it ambiguous again by doing
template <typename T = Type>
void function1(float a, Type b, typename std::enable_if<true>::type *c = 0) {
std::cout << "type\n";
}

Code duplication and template specialization (when the specialized function has different return types)

I am creating a templated class D<N>, with a method (operator(), in this case) that returns different types, depending on the value of N.
I could only make this work by creating two separate class declarations, but this came at the cost of a lot of code duplication. I also tried to create a common base class to throw the common stuff into, but I couldn't get the constructor to inherit right and don't know how idiomatic that would be as well...
#include <cstdio>
template <int N>
struct D{
int s;
D(int x):s(x){}
int yell(int x){
printf("N=%d, %d\n", N, s+x);
return s+x;
}
D<N-1> operator()(int x){
D<N-1> d(yell(x));
return d;
}
};
template <>
struct D<1>{
int s;
D(int x): s(x){}
int yell(int x){
printf("N=%d, %d\n", 1, s+x);
return s+x;
}
int operator()(int x){
return yell(x);
}
};
int main()
{
D<2> f(42);
printf("%d\n", f(1)(2));
return 0;
}
How can I make my code better looking?
You can use the Curiously Recurring Template Pattern.
template<int N, template<int> typename D> struct d_inner {
D<N-1> operator()(int x) {
return D<N-1>(static_cast<D<N>*>(this)->yell(x));
}
};
template<template<int> typename D> struct d_inner<1, D> {
int operator()(int x) {
return static_cast<D<1>*>(this)->yell(x);
}
};
template <int N> struct D : public d_inner<N, D> {
int s;
D(int x):s(x){}
int yell(int x){
printf("N=%d, %d\n", N, s+x);
return s+x;
}
};
Not that I see the utility- or purpose- of this particular object being templated, it could easily not be.
I'm not sure it is better looking: but it avoids source code duplication :
// Find a name for this ...
template<int N, template<int M> class X>
struct foo {
typedef X<N> type;
};
template< template<int M> class X >
struct foo<0,X> {
typedef int type;
};
template <int N>
struct D{
int s;
D(int x):s(x){}
int yell(int x){
printf("N=%d, %d\n", N, s+x);
return s+x;
}
typename foo<N-1,D>::type
operator()(int x){
return typename foo<N-1,D>::type(yell(x));
}
};