I have a class, classB which has several functions which I would like to specialize based on an enumerator template S.
I have the following example:
#include <iostream>
#include <string>
#include <array>
typedef std::array<double, 3> vec;
enum Op {Op1, Op2, Op3};
template<class T, enum Op S=Op1>
class classA
{
public:
class innerClassA
{
public:
void foo() const
{
std::cout <<"Operation 1" << std::endl;
}
};
};
template<class T>
class classB
{
public:
template <Op S = Op1>
void myFunc()
{
typename classA<T, S>::template innerClassA myInnerClassObj;
for (int i = 0; i < 10; i++)
myInnerClassObj.foo();
}
// Other functions the I would like to able to speciallize afterwards based on template S
void myFunc2() { std::cout << "Func 2" << std::endl; }
void myFunc3() { std::cout << "Func 3" << std::endl; }
};
template<>
void classA<vec, Op2>::innerClassA::foo() const
{
std::cout << "Operation 2" << std::endl;
}
template<>
void classA<vec, Op3>::innerClassA::foo() const
{
std::cout << "Operation 3" << std::endl;
}
int main(int argc, char** argv)
{
classB<vec> obj;
obj.myFunc();
obj.myFunc2();
obj.myFunc<Op2>();
obj.myFunc<Op3>();
return 0;
}
In the above example. The function myFunc has a template parameter based on the enumerator. In the main function, I can call the specialized version based on the value of the enumerator. I would also like to do the same for the other functions,myFunc2 however, always having to put:
template <Op S = Op1>
someFunction()
is quite bothersome. Is there any other way to specify that all functions in a class have a default template based on the enumerator?
Kind regards
No, there is not, apart from macros.
#define OPFUNC template<Op S = Op1> void
OPFUNC myFunc() {}
OPFUNC myFunc2() {}
...
#undef OPFUNC
Related
I have a template member function declared in a class that call the correct member function depending on type, and want to add some functionality to it in a daughter class, by adding a member function, like in the main.cpp example below :
#include <iostream>
class A
{
public:
template <typename T>
void handleSocketData(const T& t)
{
handleData(t);
}
void handleData(int data)
{
std::cout << data << std::endl;
}
};
class B: public A
{
public :
void handleData(std::string data) const
{
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[])
{
A a;
B b;
a.handleSocketData<int>(30);
b.handleSocketData<std::string>("Hi");
return 0;
}
My problem is that b.handleSocketData<QString>("Hi"); actually does generate a new template instance in A class as shown in the output of command /usr/bin/clang++ -DQT_CORE_LIB -isystem /usr/include/qt6/QtCore -isystem /usr/include/qt6 -isystem /usr/lib64/qt6/mkspecs/linux-g++ -g -std=gnu++17 -Xclang -ast-print -fsyntax-only main.cpp:
class A {
public:
template <typename T> void handleSocketData(const T &t) {
this->handleData(t);
}
template<> void handleSocketData<int>(const int &t) {
this->handleData(t);
}
template<> void handleSocketData<std::basic_string<char>>(const std::basic_string<char> &t) {
<recovery-expr>(this->handleData, t);
}
void handleData(int data) {
std::cout << data << std::endl;
}
};
class B : public A {
public:
void handleData(std::string data) const {
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[]) {
A a;
B b;
a.handleSocketData<int>(30);
b.handleSocketData<std::string>("Hi");
return 0;
}
So right now I have a compilation error, saying that no function handleData(const std::string& data) is found, which is normal.
A workaround we've found is to define a two-arguments template, taking the daughter class as argument (kind of visitor pattern) :
#include <iostream>
class A
{
public:
template <typename T, typename U>
void handleSocketData(U& u, const T& t)
{
u.handleData(t);
}
void handleData(int data)
{
std::cout << data << std::endl;
}
};
class B: public A
{
public :
void handleData(std::string data)
{
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[])
{
A a;
B b;
a.handleSocketData<int>(a, 30);
b.handleSocketData<std::string>(b, "Hi");
return 0;
}
What do you think ? Is there a cleaner way ?
This looks like a classic use case for CRTP. You can make A a template over a derived class Derived and then dispatch function calls to the derived class via a static_cast. For this to work, any derived class Derived must be derived from A<Derived>.
Since you seem to want to use A as a non-abstract class, you would have to add a default derived class marking it as "final". In the following code, the empty struct FinalTag serves this purpose.
#include <iostream>
struct FinalTag;
template <typename Derived=FinalTag>
class A
{
public:
template <typename T>
void handleSocketData(const T& t)
{
cast().handleData(t);
}
void handleData(int data)
{
std::cout << data << std::endl;
}
private:
constexpr auto& cast() {
return static_cast<Derived&>(*this);
}
};
struct FinalTag : A<FinalTag> {};
class B: public A<B>
{
public :
using Base = A<B>;
using Base::handleData;
void handleData(std::string data)
{
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[])
{
A a;
B b;
a.handleSocketData(30);
b.handleSocketData("Hi");
// this only works if you bring in Base::handleData in the
// derived class
b.handleSocketData(30);
return 0;
}
Live Code: https://godbolt.org/z/ns9aPjG76
This is a prototype. You would want to add a const version to the cast method for instance.
Edit:
As Jarod42 pointed out in the comments, C++23 really simplifies CRTP with "deducing this": https://godbolt.org/z/cGzMrnEhc. This isn't currently widely supported by compilers though.
A slightly different version of CRTP to the one suggested by Joerg Brech could be more suitable in some cases.
#include <iostream>
class A
{
public:
template <class Class, typename T>
void handleSocketData(const T& t)
{
static_cast<Class*>(this)->handleData(t);
}
void handleData(int data)
{
std::cout << data << std::endl;
}
};
class B: public A
{
public :
void handleData(std::string data) const
{
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[])
{
A a;
B b;
a.handleSocketData<A, int>(30);
b.handleSocketData<B, std::string>("Hi");
return 0;
}
It is very similar to your solution in the sense that we instruct handleSocketData which class it should use to call handleData from. The only difference is that the decision is made not dynamically but at compile time.
So I really need a class with the following structure, where the class is templated and arr is an array of function pointers, but I can't seem to figure out the proper syntax:
--myclass.h--
#include <vector>
template <typename T>
class MyClass {
typedef void (*fptr)(std::vector<T> data);
static void foo(std::vector<T> data);
static void bar(std::vector<T> data);
static void baz(std::vector<T> data);
static const fptr arr[3];
};
--myclass.cpp--
#include "myclass.h"
#include <vector>
template <typename T> void MyClass<T>::foo(std::vector<T> data) { ... }
template <typename T> void MyClass<T>::bar(std::vector<T> data) { ... }
template <typename T> void MyClass<T>::baz(std::vector<T> data) { ... }
template <typename T> MyClass<T>::fptr MyClass<T>::arr[3] = { &foo, &bar, &baz };
If it helps, my ultimate goal is for a fourth member function to call either foo, bar, or baz from the array so I can avoid the overhead of multiple if-else statements (my actual implementation has closer to 50 of these functions). Is there a better way to do this?
fptr is declared const, so define it const too. Also, because Sort is a template, you need typename to refer to MyClass<T>::fptr.
template<typename T>
const typename MyClass<T>::fptr MyClass<T>::arr[] = { &foo, &bar, &baz };
Side note: you won't be able to put this definition or the definitions of your static functions in a source file since they are templates.
Demo
Moreover, consider using using instead of typedef, and std::array instead of a raw array:
using fptr = void (*)(std::vector<T>);
static const std::array<fptr, 3> arr;
// [...]
template<typename T>
const std::array<typename MyClass<T>::fptr, 3> MyClass<T>::arr = { &foo, &bar, &baz };
Demo
Is there a better way to do this?
Probably, but I can't say without more details abour what you want to do exactly.
Move the whole class template into the .hpp file and initialize arr with the same signature as it was declared:
template <typename T>
class MyClass {
typedef void (*fptr)(std::vector<T> data);
static void foo(std::vector<T> data) {}
static void bar(std::vector<T> data) {}
static void baz(std::vector<T> data) {}
static const fptr arr[3];
};
template <typename T>
const typename MyClass<T>::fptr MyClass<T>::arr[] = { &foo, &bar, &baz };
You may also define arr directly:
#include <iostream>
#include <vector>
#include <array>
template <typename T>
class MyClass {
typedef void (*fptr)(std::vector<T> data);
static void foo(std::vector<T> data) {
for(int i : data) std::cout << "foo " << i << "\n";
}
static void bar(std::vector<T> data) {
for(int i : data) std::cout << "bar " << i << "\n";
}
static void baz(std::vector<T> data) {
for(int i : data) std::cout << "baz " << i << "\n";
}
public:
static constexpr std::array<fptr,3> arr = { &foo, &bar, &baz };
};
int main() {
MyClass<int> a;
a.arr[0](std::vector<int>(1));
a.arr[1](std::vector<int>(2));
a.arr[2](std::vector<int>(3));
}
Output:
foo 0
bar 0
bar 0
baz 0
baz 0
baz 0
You can use std::function and store them into a vector. Here is what I have come up with so far.
#include <exception>
#include <iostream>
#include <functional>
#include <vector>
template<typename T>
class MyClass {
private:
std::vector<std::function<void(std::vector<T>)>> myFuncs_;
public:
MyClass() = default;
void addFunc( std::function<void(std::vector<T>)> func ) {
myFuncs_.push_back(func);
}
void caller(unsigned idx, std::vector<T> v ) {
return myFuncs_.at(idx)( v );
}
static void foo(std::vector<T> data) {
std::cout << "foo() called:\n";
for (auto& d : data)
std::cout << d << " ";
std::cout << '\n';
}
static void bar(std::vector<T> data) {
std::cout << "bar() called:\n";
for (auto& d : data)
std::cout << d << " ";
std::cout << '\n';
}
};
int main() {
try {
MyClass<int> myClass;
std::vector<int> a{ 1,3,5,7,9 };
std::vector<int> b{ 2,4,6,8,10 };
std::function<void(std::vector<int>)> funcA = MyClass<int>::foo;
std::function<void(std::vector<int>)> funcB = MyClass<int>::bar;
myClass.addFunc( funcA );
myClass.addFunc( funcB );
myClass.caller(0, a);
myClass.caller(1, b);
} catch( std::runtime_error& e ) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
-Output-
MyClass::foo() was called:
1 3 5 7 9
MyClass::bar() was called:
2 4 6 8 10
Not sure if this is exactly what you was looking for. In this example MyClass::caller(...) takes two parameters, the index into the vector for which function pointer you want, and the parameter or data that the function requires as input.
This code:
#include <iostream>
class A {};
class B : public A {};
class C {
public:
template <typename T>
void x(const T& t) {
std::cout << "template" << std::endl;
}
void x(const A*& a) {
std::cout << "a" << std::endl;
}
void x(const int& a) {
std::cout << "int" << std::endl;
}
template <typename T>
void y(T t) {
std::cout << "template" << std::endl;
}
void y(A* a) {
std::cout << "a" << std::endl;
}
void y(int a) {
std::cout << "int" << std::endl;
}
template <typename T>
void z(const T& t) {
std::cout << "template" << std::endl;
}
};
// Does not compile
// template <>
// void C::z(const A*& a) {
// std::cout << "a" << std::endl;
// }
template <>
void C::z(const int& a) {
std::cout << "int" << std::endl;
}
int main(int argc, char** argv) {
C c;
c.x(new A());
c.x(new B());
c.x(1);
c.y(new A());
c.y(new B());
c.y(1);
c.z(new A());
c.z(new B());
c.z(1);
}
Prints:
template
template
int
a
template
int
template
template
int
I have the following questions about that:
Why does void C::z(const int& a) compile but void C::z(const A*& a) does not?
What is a reasonable solution to problem? I need to have a templated function for generically handling a wide variety of arguments, but a large set of classes with a common base needs to be handled specifically. I need some approach that will print a a int.
Edit: Thanks to the suggestion of #AndyG I was able to resolve this with some type_traits and the code below:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <iostream>
class A {};
class B : public A {};
class C {
public:
template <typename T>
typename boost::disable_if<boost::is_base_of<A, typename boost::remove_pointer<T>::type>, void>::type x(const T& t) {
std::cout << "template" << std::endl;
}
void x(A*const& a) {
std::cout << "a" << std::endl;
}
void x(const int& a) {
std::cout << "int" << std::endl;
}
};
int main(int argc, char** argv) {
C c;
c.x(new A());
c.x(new B());
c.x(1);
}
The answer is because a const on a pointer type is a little weird.
What you want is this:
template <>
void C::z( A*const& a) {
std::cout << "a" << std::endl;
}
const needs to be read right to left. Since z accepts a T&, when you want to specialize for A* you need to place the const after A* instead of in front.
Demo
I have a template method inside a template class.
I read that a method can not be specialized without specialize the class before.
But I want to factorize some of theses methods, is it possible ?
Example :
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num> class A {
private:
num n;
public:
template<typename type>
void multiplyBy(); // by 1 if <int> or 1,5 if <float>
}; // A
template<> template<> void A<One>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
template<> template<> void A<One>::multiplyBy<float>() {
std::cout << 1.5*n.number << std::endl;
}
template<> template<> void A<Two>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
template<> template<> void A<Two>::multiplyBy<float>() {
std::cout << 1.5*n.number << std::endl;
}
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
A stackoverflow related question : C++ specialization of template function inside template class
In particular this comment : C++ specialization of template function inside template class
Have I to deduct than there is no way to factorize multiplyBy(), for one for int and an other for float ?
As english is not my natural language maybe I miss something simple, maybe a workaround with partial-specialization.
Edit : put A::n in private to match even better my problem.
You might use tag dispatching:
#include <iostream>
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num>
class A {
public:
num n;
private:
template<typename> struct Tag {};
void multiplyBy(Tag<int>) {
std::cout << 1.0*n.number << std::endl;
}
void multiplyBy(Tag<float>) {
std::cout << 1.5*n.number << std::endl;
}
public:
template<typename type>
void multiplyBy() {
multiplyBy(Tag<type>());
}
};
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
But I want to factorize some of theses methods, is it possible ?
You probably know that you cannot use:
template<> template<> void A<One>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
without specializing A<One>.
You can do something along the lines of:
#include <iostream>
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num, typename type = int> struct MultiplyBy {
static void doit(num n)
{
std::cout << 1.0*n.number << std::endl;
}
};
template<typename num> struct MultiplyBy<num, float> {
static void doit(num n)
{
std::cout << 1.5*n.number << std::endl;
}
};
template<typename num> class A {
public:
num n;
template<typename type>
void multiplyBy()
{
MultiplyBy<num, type>::doit(n);
}
};
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
I would like to write a member function which detects if the instantiated object is const.
To give a simple example, we can consider the following class definition
class Foo{
public:
void constnessChecker(){
bool isConst;
// MORE CODE GOES HERE...
if (isConst) {
std::cout << "This instance is const! << std::endl;
} else {
std::cout << "This instance is not const! << std::endl;
}
}
};
and the following code
int main(){
Foo foo1;
Foo const foo2;
foo1.constnessChecker();
foo2.constnessChecker();
}
which should produce
This instance is not const!
This instance is const!
Is this possible?
Provide const and non-const overloads:
class Foo
{
public:
void constnessChecker(){
std::cout << "This instance is not const\n";
}
void constnessChecker() const {
std::cout << "This instance is const\n";
}
....
};
In the style of boost::is_const or std::is_const, you can also write up the following:
#include <iostream>
template <typename T>
struct is_const
{
static const bool value = false;
};
template <typename T>
struct is_const<const T*>
{
static const bool value = true;
};
struct S
{
void f() const
{
std::cout << is_const<decltype(this)>::value << std::endl;
}
void f()
{
std::cout << is_const<decltype(this)>::value << std::endl;
}
int m;
};
int main(int argc, char** argv)
{
const S& cs = S(); // note that choosing a const-ref is merely to force the compiler to choos S::f() const!
cs.f (); // prints 1
S().f (); // prints 0
return 0;
}
I haven't looked at the implementation of std::is_const but for some reason it returns false where the above is_const returns true.
Note: Obviously you need support for decltype and thus the above will only work for C++11 compliant compilers.