I want to define a class, called Nested here, that will contains two or more (one here) data members that support arithmetic operations using expression templates, for example an std::valarray. For this class itself, I am defining its own expression templates and I want to "forward" the arithmetic operations down to the members.
A minimal (non)working example is given below:
#include <iostream>
#include <valarray>
template <typename E>
struct NestedExpr {
operator const E& () const {
return *static_cast<const E*>(this);
}
};
template <typename A>
class Nested : public NestedExpr <Nested<A>>{
private:
A a;
public:
Nested(const A& _a) : a(_a) {}
template <typename E>
inline Nested<A>& operator = (const NestedExpr<E>& _expr) {
const E& expr(_expr);
a = expr.get_a();
return *this;
}
inline A& get_a() { return a; }
inline const A& get_a() const { return a; }
};
// ================================================================= //
template <typename ARG, typename S>
class NestedMul : public NestedExpr<NestedMul<ARG, S>> {
public:
const ARG& arg;
const S s;
NestedMul(const ARG& _arg, S _s) : arg(_arg), s(_s) {}
inline auto get_a() const { return arg.get_a() * s; };
};
template< typename ARG, typename S>
inline NestedMul<ARG, S> operator * (S s, const NestedExpr<ARG>& arg) {
return {arg, s};
}
// ================================================================= //
template <typename ARG1, typename ARG2>
class NestedAdd : public NestedExpr<NestedAdd<ARG1, ARG2>> {
public:
const ARG1& arg1;
const ARG2& arg2;
NestedAdd(const ARG1& _arg1, const ARG2& _arg2)
: arg1(_arg1), arg2(_arg2) {}
inline auto get_a() const { return arg1.get_a() + arg2.get_a(); };
};
template<typename ARG1, typename ARG2>
inline NestedAdd<ARG1, ARG2>
operator + (const NestedExpr<ARG1>& arg1, const NestedExpr<ARG2>& arg2) {
return {arg1, arg2};
}
int main () {
std::valarray<double> x1 = {4.0};
std::valarray<double> x2 = {3.0};
std::valarray<double> x3 = {0.0};
std::valarray<double> x4 = {0.0};
auto a = Nested<std::valarray<double>>(x1);
auto b = Nested<std::valarray<double>>(x2);
auto c = Nested<std::valarray<double>>(x3);
// this returns 21
c = 2*a + 3*b;
std::cout << c.get_a()[0] << std::endl;
// works as expected, returns 17
x4 = 2*x1 + 3*x2;
std::cout << x4[0] << std::endl;
}
The output of this program is
21
17
i.e. forwarding the expression down to the member does not seem to provide the expected result obtained directly from using the valarrays.
Any help here is appreciated.
In the below function definition:
inline auto get_a() const { return arg.get_a() * s; };
your expected behavior is that auto deduces std::valarray<double>, that is, the result type of a multiplication of std::valarray<double> and int which is a new object that already stores values multiplied by the integer.
This is how operator* is defined [valarray.binary]/p2:
template <class T>
valarray<T> operator*(const valarray<T>&,
const typename valarray<T>::value_type&);
However, there's the following paragraph in the standard [valarray.syn]/p3:
Any function returning a valarray<T> is permitted to return an object of another type, provided all the const member functions of valarray<T> are also applicable to this type. This return type shall not add more than two levels of template nesting over the most deeply nested argument type.
This type must be convertible to std::valarray<double>, but itself, for optimization purposes, may not represent the actual result before that conversion happens.
That is, here's the actual type deduced for auto by GCC:
std::_Expr<std::__detail::_BinClos<std::__multiplies
, std::_ValArray
, std::_Constant, double, double>, double>
and here's what Clang uses:
std::__1::__val_expr<std::__1::_BinaryOp<std::__1::multiplies<double>,
std::__1::valarray<double>, std::__1::__scalar_expr<double> > >
In other words, you are returning by value an object which probably defers the actual computations. In order to do so, those intermediate objects need to store somehow the deferred subexpressions.
Inspecting GCC libstdc++'s implementation, one can find the following representation:
template <class _Oper, class _FirstArg, class _SecondArg>
class _BinBase
{
public:
typedef typename _FirstArg::value_type _Vt;
typedef typename __fun<_Oper, _Vt>::result_type value_type;
_BinBase(const _FirstArg& __e1, const _SecondArg& __e2)
: _M_expr1(__e1), _M_expr2(__e2) {}
// [...]
private:
const _FirstArg& _M_expr1;
const _SecondArg& _M_expr2;
};
Note that subexpressions are stored as references. This means that in the definition of get_a():
return arg1.get_a() + arg2.get_a();
_M_expr1 and _M_expr2 are bound to temporary objects:
arg1.get_a()
arg2.get_a()
i.e., intermediate objects which are the results of multiplications, whose lifetime ends as soon as NextedAdd::get_a() exits, leading to undefined behavior when the result is eventually computed, in particular, when the implementation attempts to access each individual element of that intermediate subexpressions:
value_type operator[](size_t __i) const
{
return _Oper()(_M_expr1[__i], _M_expr2[__i]);
}
A quick solution would be to use the following return type:
std::decay_t<decltype(arg.get_a())> get_a() const { return arg.get_a() * s; }
This will recursively ensure that the final result type of any operation will be whatever the original type T in Nested<T> was, i.e., std::valarray<double>.
DEMO
Related
This question already has answers here:
Why does this compiler warning only show for int but not for string? "type qualifiers ignored on function return type"
(4 answers)
Closed 8 months ago.
I have the following code:
#include <concepts>
#include <functional>
#include <iostream>
template<typename T>
concept OperatorLike = requires(T t, const std::string s) {
{ t.get_string(s) } -> std::same_as<const std::string>;
{ t.get_int(s) } -> std::same_as<const int>;
};
template<typename T, typename O>
concept Gettable = requires(T t, O op) {
t.apply_get(0, op);
t.apply_post(0, op); };
template<std::semiregular F>
class RestApiImpl {
F m_get_method;
public:
RestApiImpl(F get = F{}) : m_get_method{std::move(get)} {}
void register_get(F functor) {
m_get_method = std::move(functor);
}
template<OperatorLike IF>
requires std::invocable<F, const int, IF>
void apply_get(const int req, IF interface){
m_get_method(req, std::move(interface));
}
template<OperatorLike IF>
requires std::invocable<F, const int, IF>
void apply_post(const int req, IF interface){
m_get_method(req, std::move(interface));
}
};
class ASpecificJSONLibrary{
public:
std::string operator[](std::string key){
return key + "_withLambda";
}
};
class Server{
public:
ASpecificJSONLibrary libObj; // this is a
struct impl;
void run(Gettable<impl> auto& api){
api.apply_get(0, impl(*this));
}
struct impl {
public:
Server& m_server;
impl(Server& server ) : m_server(server){}
const std::string get_string(const std::string key) {
return (m_server.libObj)[key];
};
const int get_int(std::string const key) {
return 1;
}
};
};
int main(){
auto get = [](int, OperatorLike auto intf){
std::string dummy = "dummy";
std::cout << intf.get_string(dummy);
};
RestApiImpl api(get);
Server server;
server.run(api);
return 0;
};
If remove the line t.get_int(s) } -> std::same_as<int>; from the concept OperatorLike everything seems to work as it should. I am not sure why adding this additional requirement gives me a compile error. The compile error also refers only to the fact that the there is no matching function to the run method, which is because the Gettable concept is not satisfied. But the root cause looks like it is the OperatorLike concept
Another observation just made is that if I remove all the consts from the operatorLike concept it all just seem to work including the additional requirements
The compound requirement
{ t.get_int(s) } -> std::same_as<const int>;
tests whether decltype((t.get_int(s))) is the same as const int. However, that is a pointless test, because there are no const prvalues of non-class type and these would be the only expressions for which decltype could result in const int.
A prvalue of non-class type will always have its const stripped. So even if get_int is declared to return const int, the type of the call expression t.get_int(s) will always be int, not const int.
In general having top-level const on a return type is almost always useless. The only use case I can think of is a class type return value for which you want to disallow calling non-const member functions without storing in a variable first, but there are better ways of achieving that (e.g. &-qualified member functions).
I know this type of errors occur when a base class is only forward declared, but in my case it's fully implemented as far as I can tell:
I'm trying to create a unit system which would only compile if the correct units are used, employing literals and algebraic operators.
I start with a base class Units which is just a wrapper over T, and is inherited by all the other units.
Then I define the allowed algebraic operators, which should return the correct units.
I get
error: invalid use of incomplete type ‘class Units<T>’
[build] 107 | return Mps{static_cast<T>(rhs) / static_cast<T>(lhs)};
for this code:
template<typename T>
class Units
{
protected:
T val;
public:
constexpr explicit Units(T val) : val(val) { }
constexpr explicit operator T&() { return val; }
constexpr explicit operator T() const { return val; }
constexpr auto operator<=>(const Units<T> rhs) {
return val <=> rhs.val;
}
constexpr bool operator==(const Units<T> rhs) const { return val == rhs.val; }
};
template<typename T>
class Meters : public Units<T>
{
using typename Units<T>::Units;
};
template<typename T>
class Seconds : public Units<T>
{
using typename Units<T>::Units;
};
template<typename T>
class Mps : public Units<T>
{
using typename Units<T>::Units;
};
constexpr Meters<long double> operator "" _km(long double km) {
return Meters<long double>{1000 * km};
}
constexpr Seconds<long double> operator "" _s(long double s) {
return Seconds<long double>{s};
}
constexpr Mps<long double> operator "" _mps(long double s) {
return Mps<long double>{s};
}
template<typename T>
constexpr Mps<T> operator / (const Meters<T> &&rhs, const Seconds<T> &&lhs) {
return Mps{static_cast<T>(rhs) / static_cast<T>(lhs)};
}
int main() {
return 1_km / 2_s == 500_mps
}
Looks like the compiler is confused and the warning is misleading. Provide the missing template argument to fix it:
return Mps<T>{static_cast<T>(rhs) / static_cast<T>(lhs)};
^^^
You can (probably) define a deduction guide if you wish to avoid specifying the argument explicitly.
Other issues:
Missing semicolon.
Your operators are for floating point, but you use integer in 1_km; that won't work. Either use floating point literal, or add an overload for integers.
using typename Units<T>::Units; is wrong. Lose the typename.
For sorting user defined typed objects in a flexible way (i.e. by naming a member variable) I wrote a template to generate lambdas to do the comparison. Additionally to chain comparisons of different member variables in case of equality I wrote a second template. It works so far but I want bpth templates to be completely independent from any concrete types. Therefore I have to get a class type from a class member pointer type.
This is my user defined example type:
struct Person { string name; int age, height; };
To sort objects of it by looking at e.g. the age I want to write it like:
auto result = max_element(persons.begin(), persons.end(), order_by(&Person::age));
This works with the template:
template<class F> //F is Person::* e.g. &Person::age
auto order_by(F f) {
return [f](const Person& smaller, const Person& bigger) {
return smaller.*f < bigger.*f;
};
}
To be able to chain multiple comparisons in case of equal values like this:
result = max_element(persons.begin(), persons.end(), order_by(&Person::age) | order_by(&Person::height));
I wrote the template:
//compose two orderings :
template<class F1, class F2>
auto operator|(F1 f1, F2 f2) {
return [f1, f2](auto a, auto b) {
auto res = f1(a, b);
auto inv_res = f1(b, a);
if (res != inv_res)
return res;
return f2(a, b);
};
}
Here the first comparison is done and if it detects that a==b (a is not smaller than b and b is not smaller than a) it uses the second comparison function.
What I want to achieve is to be independent of the Person type in the first template. How could this be solved?
You can easily extract the class and type of the pointer-to-member in your first template with some small modifications.
template<class Class, class Type>
auto order_by(Type Class::* f) {
return [f](const Class& smaller, const Class& bigger) {
return smaller.*f < bigger.*f;
};
}
I would forward job to std::tuple with something like:
template <typename... Projs>
auto order_by(Projs... projs) {
return [=](const auto& lhs, const auto& rhs) {
return std::forward_as_tuple(std::invoke(projs, lhs)...)
< std::forward_as_tuple(std::invoke(projs, rhs)...);
};
}
with usage
result = std::max_element(persons.begin(), persons.end(), order_by(&Person::age, &Person::height));
ranges algorithms (C++20 or range-v3) separate comparison from projection, so you might have (by changing order_by to project_to):
result = ranges::max_element(persons, std::less<>{}, project_to(&Person::age, &Person::height));
You can get the class type from the type of a pointer to member like this:
#include <type_traits>
#include <iostream>
struct Foo {
int bar;
};
template <typename T>
struct type_from_member;
template <typename M,typename T>
struct type_from_member< M T::* > {
using type = T;
};
int main()
{
std::cout << std::is_same< type_from_member<decltype(&Foo::bar)>::type, Foo>::value;
}
Output:
1
Because type_from_member< decltype(&Foo::bar)>::type is Foo.
So you could use it like this:
template<class F> //F is Person::* e.g. &Person::age
auto order_by(F f) {
using T = typename type_from_member<F>::type;
return [f](const T& smaller, const T& bigger) {
return smaller.*f < bigger.*f;
};
}
I found an excellent explanation of expression templates here. In the article, we find a basic expression template implementation for arithmetic, as follows (slightly adapted):
#include <iostream>
template <typename T>
struct plus {
T operator()(const T a, const T b) const { return a + b; }
};
template <class ExprT>
struct exprTraits {
typedef ExprT expr_type;
};
template <class ExprT1, class ExprT2, class BinOp>
class BinaryExpr {
public:
BinaryExpr(ExprT1 e1, ExprT2 e2, BinOp op = BinOp()) : _expr1(e1), _expr2(e2), _op(op) {}
double eval() const { return _op(_expr1.eval(), _expr2.eval()); }
private:
typename exprTraits<ExprT1>::expr_type _expr1;
typename exprTraits<ExprT2>::expr_type _expr2;
BinOp _op;
};
class Literal {
public:
Literal(const double v) : _val(v) {}
double eval() const { return _val; }
private:
const double _val;
};
template <>
struct exprTraits<double> {
typedef Literal expr_type;
};
class Variable {
public:
Variable(double& v) : _val(v) {}
double eval() const { return _val; }
void operator+=(double x) { _val += x; }
private:
double& _val;
};
class SpecialVariable : public Variable {
public:
SpecialVariable(double& v) : Variable{v} {};
double eval() const { return -1000.0; }
};
template <class ExprT1, class ExprT2>
BinaryExpr<ExprT1, ExprT2, plus<double>> operator+(ExprT1 e1, ExprT2 e2) {
return BinaryExpr<ExprT1, ExprT2, plus<double>>(e1, e2);
}
There are three type of nodes, Literal, Variable and SpecialVariable which is a subclass of the latter. The traits are there to allow for built-in types like double in the expressions without wrapping them with Literal.
Now, suppose I want to do something particular when I add a double and a Variable and plus-assign it to a Variable. I add following member function to Variable:
void operator+=(BinaryExpr<double, Variable, plus<double>> expr) { _val += 1000.0; }
and write a little test program:
int main(int argc, char const* argv[]) {
double xd = 2.0, yd = 5.0;
Variable x{xd};
SpecialVariable y{yd};
x += 3.0 + y;
std::cout << "result : " << std::to_string(x.eval()) << "\n";
return 0;
}
This, however, only works with Variables and not SpecialVariables, i.e. I get following compiler error:
error: no match for ‘operator+=’ (operand types are ‘Variable’ and ‘BinaryExpr<double, SpecialVariable, plus<double> >’) x += 3.0 + y;
note: no known conversion for argument 1 from ‘BinaryExpr<double, SpecialVariable, plus<double> >’ to ‘BinaryExpr<double, Variable, plus<double> >’
which is completely reasonable since template classes do not necessarily have a relation if their template arguments have one.
Question: how can I write one operator+= that accepts expression templates with types and possibly their subtypes? I've not seen an expression template tutorial that addresses this particular problem.
Question: how can I write one operator+= that accepts expression templates with types and possibly their subtypes?
Using std::is_base_of and SFINAE
template <typename V>
std::enable_if_t<std::is_base_of_v<Variable, V>>
operator+= (BinaryExpr<double, V, plus<double>> expr)
{ _val += 1000.0; }
The preceding code compile in C++17.
If you're using C++14 you have to use
std::is_base_of<Variable, V>::value
instead of
std::is_base_of_v<Variable, V>
If you're using C++11 you have to use
typename std::enable_if<std::is_base_of<Variable, V>::value>::type
instead of
std::enable_if_t<std::is_base_of_v<Variable, V>>
There are a few questions on SO that address passing function pointers as parameters/arguments (here, here, here, etc.). In fact, I asked a related question the other day. However, this question is a little different.
My problem is that I am writing a class that I want to be extremely flexible.
What I have now works for non-member functions. It is posted below
template <typename T>
class MyClass
{
private:
typedef double (*firstFunctionPtr) (const T &var);
typedef bool (*secondFunctionPtr)(const T &var);
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc,
secondFunctionPtr secondFunc);
};
template<typename T>
MyClass<T>::MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc),
{}
However, this falls apart when I need to initialize with a pointer to a member function of some other, arbitrary, class, which, unfortunately for me, happens to be a common use case for my purposes.
This answer suggests that
In a proper C++ interface you might want to have a look at having your function take templated argument for function objects to use arbitrary class types.
However, I have not been able to make this compile. I've tried templating my typedefs (using the C++11 aliasing approach), and I've tried adding a second template parameter to the class to handle the calling class of those member functions, but neither approach has worked.
This Q/A seems to be getting towards what I'm trying to do, but I can't make heads or tails of it.
Can someone please explain how I might modify my class to handle arbitrary member functions pointers being passed in?
Furthermore, is it possible to make it so that it can handle either arbitrary member functions or non-member functions?
Lastly, is it possible to do this with templates?
For the record, I'm trying to avoid using the functional header, but it may be a fool's errand not to use it.
If you want MyClass to be a template that can hold both free function
pointers of types:
double (*)(const T &var);
bool (*)(const T &var);
for some parameter type T, or alternatively member-function
pointers of types:
double (C::*)(const T &var);
bool (C::*)(const T &var);
for some parameter types C and T then, MyClass must be parameterized
by both T and C and you require two specializations:
Where C is some non-class type
Where C is any class type
In case (1), the non-class type C cannot possibly have member functions,
so that one will implement the free-function pointer specialization.
In case (2), the class C could be one that has member functions, so that one
will implement the member-function pointer specialization.
The obvious choice for a non-class type C is void. So we can make C
default to void:
Primary template
template<typename T, typename C = void>
struct MyClass;
So that:
MyClass<T>
will be the free function pointer specialization for T, and:
MyClass<T,C>
for any C other than void, will be the member-function pointer specialization.
As you may know you can use std::enable_if
and SFINAE to make the compiler
chose one specialization of a class template or another, depending on whether one
of its template parameters U satisfies some compiletime test. You could take
that approach here, but another one is available that does not require that apparatus:
Starting with the primary template, we would just like to have:
Free function specialization
template<typename T>
struct MyClass<T>
{
... for free function pointers ...
};
and:
Member function specialization
template<typename T, typename C>
struct MyClass<T,C>
{
... for member function pointers ...
};
But we can't have just that, because the member function "specialization" has exactly
the same template parameters as the primary template. Which means it isn't
a specialization, and the compiler won't allow it.
You can easily remove that problem, however, simply by giving the primary
template one more defaulting template parameter that it doesn't need, but whose
presence allows both those specializations to stand.
New primary template
template <typename T, typename C = void, typename Default = void>
struct MyClass;
So here is an illustrative solution:
// Primary template
template <typename T, typename C = void, typename Default = void>
struct MyClass;
// Free function specialization
template <typename T>
struct MyClass<T>
{
using firstFunctor_t = double(*)(T const &);
using secondFunctor_t = bool(*)(T const &);
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(T const & var) {
return _firstFunc(var);
}
bool callSecond(T const & var) {
return _secondFunc(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
// Member function specialization
template <typename T, typename C>
struct MyClass<T,C>
{
using firstFunctor_t = double(C::*)(T const &);
using secondFunctor_t = bool(C::*)(T const &) const;
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(C & obj, T const & var) {
return (obj.*_firstFunc)(var);
}
double callFirst(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_firstFunc)(var);
}
bool callSecond(C & obj, T const & var) {
return (obj.*_secondFunc)(var);
}
bool callSecond(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_secondFunc)(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
In the member function specialization, notice a couple of points that you might
not have considered:-
I decided that the second member function I want to store shall be a
const member function. It's more than likely that a member function of C
that take a T const & argument and returns bool will be a const member
function, isn't it? And if so, then that const-ness has to be part of
the member-function type definition that I use in the specialization:
using secondFunctor_t = bool(C::*)(T const &) const;
or attempts to instantiate the specialization with any bool (C::*)(T const &) const
will fail to compile.
Also, I have provided two overloads for each of MyClass<T,C>::callFirst
and MyClass<T,C>::callSecond, one with arguments:
C & obj, T const & var
and another with arguments:
C const & obj, T const & var
Without the second, attempts to call either MyClass<T,C>::callFirst
or MyClass<T,C>::callSecond with an obj that is const will fail to
compile.
For program to demo this solution you can append:
#include <iostream>
#include <string>
double foo(std::string const & s)
{
return std::stod(s);
}
bool bar(std::string const & s)
{
return s.size() > 0;
}
struct SomeClass
{
SomeClass(){};
double foo(std::string const & s) {
return ::foo(s);
}
bool bar(std::string const & s) const {
return ::bar(s);
}
};
int main()
{
MyClass<std::string> my0{foo,bar};
std::cout << std::boolalpha;
std::cout << my0.callFirst("1.11") << std::endl;
std::cout << my0.callSecond("Hello World") << std::endl;
MyClass<std::string,SomeClass> my1{&SomeClass::foo,&SomeClass::bar};
SomeClass thing;
std::cout << my1.callFirst(thing,"2.22") << std::endl;
std::cout << my1.callSecond(thing,"Hello World") << std::endl;
SomeClass const constThing;
std::cout << my1.callFirst(constThing,"3.33") << std::endl;
std::cout << my1.callSecond(constThing,"Hello World") << std::endl;
return 0;
}
See it live
You said that you want this template to be "extremely flexible". The
illustrated solution is fitted to your example, but you might be
interested in know that it isn't nearly as flexible as you could get.
For both free functions and member functions, with additional variadic template
parameters, your template could store and call [member] functions with
arbitary return types and arbitary numbers of arguments of arbitrary types.
See this question and
answer.
I will sugest to create a helper object which will store the type you want to work with:
template <typename RETURN, typename TYPE, typename CLASS>
struct function_pointer
{ using type_t = RETURN (CLASS::*)(const TYPE &); };
template <typename RETURN, typename TYPE>
struct function_pointer<RETURN, TYPE, std::nullptr_t>
{ using type_t = RETURN (*)(const TYPE &); };
This type will create a member-function-pointer if a class is provided as third parameter and a function-pointer otherwise. Now, we can use this helper in MyClass:
template <typename T, typename CLASS = std::nullptr_t>
class MyClass
{
using firstFunctionPtr = typename function_pointer<double, T, CLASS>::type_t;
using secondFunctionPtr = typename function_pointer<bool, T, CLASS>::type_t;
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
void call_first(CLASS &c, const T&v) { (c.*_firstFunc)(v); }
void call_second(CLASS &c, const T&v) { (c.*_secondFunc)(v); }
void call_first(const T&v) { (_firstFunc)(v); }
void call_second(const T&v) { (_secondFunc)(v); }
};
I've added call_* functions just to show a use case, which will be as below:
// Some class with the expected function signatures
struct S1
{
int i = 0;
double d(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Another class with the expected function signatures
struct S2
{
double d(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Free function with which could have the expected function signature
template <typename R>
R f(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
Using MyClass with an arbitrary class (S1):
S1 a{1}, b{2};
S2 c, d;
MyClass<int, S1> MCiS1(&S1::d, &S1::b);
MCiS1.call_first(a, 111); // Prints -> 1 double S1::d(const int&)
MCiS1.call_second(b, 222); // Prints -> 2 bool S1::b(const int&)
MCiS1.call_first(c, 111); // Error decltype(c) is not S1.
MCiS1.call_second(d, 222); // Error decltype(d) is not S1.
Using MyClass with a different class (S2):
MyClass<int, S2> MCiS2(&S2::d, &S2::b);
MCiS2.call_first(c, 111); // Prints -> double S2::d(const int&)
MCiS2.call_second(d, 222); // Prints -> bool S2::b(const int&)
MCiS2.call_first(a, 111); // Error decltype(c) is not S2.
MCiS2.call_second(b, 222); // Error decltype(d) is not S2.
Using MyClass with non-member functions:
MyClass<int> MCi(f<double>, f<bool>);
MCi.call_first(111); // Prints -> R f(const int&) [with R = double]
MCi.call_second(222); // Prints -> R f(const int&) [with R = bool]
Check the live demo Here.
All you need to do is bind the object instance for the member function pointer as a first argument.
struct foo {
float bar1(const type &var);
bool bar2(const type &var);
};
foo my_foo;
auto f1 = std::bind(&foo::bar1, my_foo, _1);
auto f2 = std::bind(&foo::bar2, my_foo, _1);
MyClass<type> my_obj(f1, f2);