You know, we can wrap or store a lambda function to a std::function:
#include <iostream>
#include <functional>
int main()
{
std::function<float (float, float)> add = [](float a, float b)
// ^^^^^^^^^^^^^^^^^^^^
{
return a + b;
};
std::cout << add(1, 2) << std::endl;
}
My question is around std::function, as you can see it is a template class but it can accept any kind of function signature.
For example float (float, float) in this form return_value (first_arg, second_arg).
What's the structure of std::function and how does it accept a function signature like x(y,z) and how it works with it? Is float (float, float) a new valid expression in C++?
It uses some type erasure technique.
One possibility is to use mix subtype polymorphism with templates. Here's a simplified version, just to give a feel for the overall structure:
template <typename T>
struct function;
template <typename Result, typename... Args>
struct function<Result(Args...)> {
private:
// this is the bit that will erase the actual type
struct concept {
virtual Result operator()(Args...) const = 0;
};
// this template provides us derived classes from `concept`
// that can store and invoke op() for any type
template <typename T>
struct model : concept {
template <typename U>
model(U&& u) : t(std::forward<U>(u)) {}
Result operator()(Args... a) const override {
t(std::forward<Args>(a)...);
}
T t;
};
// this is the actual storage
// note how the `model<?>` type is not used here
std::unique_ptr<concept> fn;
public:
// construct a `model<T>`, but store it as a pointer to `concept`
// this is where the erasure "happens"
template <typename T,
typename=typename std::enable_if<
std::is_convertible<
decltype( t(std::declval<Args>()...) ),
Result
>::value
>::type>
function(T&& t)
: fn(new model<typename std::decay<T>::type>(std::forward<T>(t))) {}
// do the virtual call
Result operator()(Args... args) const {
return (*fn)(std::forward<Args>(args)...);
}
};
(Note that I overlooked several things for the sake of simplicity: it cannot be copied, and maybe other problems; don't use this code in real code)
Related
Using C++ 17. I have the following:
template <typename T>
using ptr_t = std::shared_ptr<const T>;
class some_type;
class A { some_type foo() const; }
class B { some_type foo() const; }
class C { some_type foo(int) const; }
std::variant<ptr_t<A>, ptr_t<B>, ptr_t<C>>;
A variant holds shared_ptr(s) to different types. All expected to have function foo() that may be void or take a parameter. I will then have a visitor that would correctly dispatch foo, something like this (conceptually):
struct visitor
{
template <typename T>
ptr_t<some_type> operator()(const T& config) const
{
if constexpr (// determine if foo() of the underlying type of a shared_ptr can be called with int param)
return config->foo(15);
else
return config->foo();
}
is there a way to say this? I tried various ways but can't come with something that compiles. Template parameter, T, is ptr_t<A|B|C>.
std::is_invocable_v<Callable, Args...> is the way to go. Unfortunatelly, it will not compile just like that with if constexpr. It will either fail because "there is no operator()() overload", or there is no overload for operator taking Args....
I suggest you add a wrapper class for a callable and use it with a specialized alias template of std::variant instead of writing your own visitor. It will allow you to use std::visit seamlessly.
#include <type_traits>
#include <variant>
template <typename Callable>
class wrapped_callable
{
Callable c;
public:
wrapped_callable(Callable c)
: c(c)
{}
template <typename ... Args>
constexpr decltype(auto) operator()(Args &&... args) const
{
return _invoke(std::is_invocable<Callable, Args...>{}, c, std::forward<Args>(args)...);
}
private:
using _invocable = std::true_type;
using _non_invocable = std::false_type;
template <typename T, typename ... Args>
constexpr static decltype(auto) _invoke(_invocable, const T& t, Args &&... args)
{
return t(std::forward<Args>(args)...);
}
template <typename T, typename ... Args>
constexpr static decltype(auto) _invoke(_non_invocable, const T& t, Args ... args)
{
return t();
}
};
template <typename ... T>
using variant_callable = std::variant<wrapped_callable<T>...>;
struct int_callable
{
int operator()(int i) const
{
return i;
}
};
struct non_callable
{
int operator()() const
{
return 42;
}
};
#include <iostream>
int main()
{
using variant_t = variant_callable<int_callable, non_callable>;
// 23 is ignored, 42 is printed
std::visit([](const auto &callable){
std::cout << callable(23) << '\n';
}, variant_t{non_callable()});
// 23 is passed along and printed
std::visit([](const auto &callable){
std::cout << callable(23) << '\n';
}, variant_t{int_callable()});
}
Program returned: 0
42
23
https://godbolt.org/z/e6GzvW6n6
But The idea is not to have any specialization for all types in a variant as it will then require changing the visitor code every time a new type is added.
That is what template alias of std::variant<wrapped_callable<T>...> for. You just add append a new type to the list, that's it.
Take notice, that it does not depend on if constexpr. So if you manage to provide your own variant and is_invocable_v, it will work for C++14. For C++11 possibly, but some modifications regarding constexpr functions might be needed.
Of course you can implement your visitor in the same manner if you want to use std::shared_ptr istead of a callable.
But I don't see any reason to use:
visitor + smart pointer. Just use a smart pointer - it will give you runtime polymorphism in a "classic" way (via virtual inheritence)
why std::shared_ptr? Do you really need to share the ownership? Just stick with std::unique_ptr
The goal
I try to create a set of classes that removes boilerplate code for implementing extensions to a game in C++.
For that, I have a designated value class, that can hold one of the following types:
float, std::string, bool, std::vector<value>, void
For that, I would like to have a host class to which I can add one or more method instances like follows:
using namespace std::string_literals;
host h;
h.add(
method<bool, req<std::string>, req<std::string>, opt<bool>>("compare_strings"s,
[](std::string s_orig, std::string s_comp, std::optional<bool> ingore_case) -> bool {
if (ignore_case.has_value() && ignore_case.value()) {
// ... lowercase both
}
return s_orig.compare(s_comp) == 0;
}));
Note that req<T> should be a meta info that a given value is required, opt<T> a meta info that a given value is not required and may only be provided after all required parameters.
The host class now contains a method execute(std::string function, std::vector<value> values) with function and values originating from a method getting char* for method and ´char** argv+ int argcfor values. Theexecutemethod now is supposed to call the correctmethod` instances function
value host::execute(std::string function, std::vector<value> values) {
// get matching method group
std::vector<method> mthds = m_methods[function];
// get matching parameter list
for (method& mthd : mthds) {
if (mthd.can_call(mthds, values)) {
// call generic method
auto res = mthd.call_generic(values);
// pass result back to callee
// return [...]
}
}
// return error back to callee
// return [...]
}
which means that the actual method class now needs to mangle two methods properly can_call and call_generic.
The value class has corresponding template<typename T> bool is() and template<typename T> T get() methods.
What remains
I did have other attempts at this, but as those failed, I deleted them (not very smart in hindside, but needed to get the whole thing out as another person relied on the results working) and now cannot figure out another attempt then prior ... so this is what I am left with as of now:
class method_base
{
public:
template<typename T> struct in { using type = T; };
template<typename T> struct opt { using type = T; };
public:
virtual bool can_call(std::vector<sqf::value> values) = 0;
virtual sqf::value call_generic(std::vector<sqf::value> values) = 0;
};
template<typename T, typename ... TArgs>
class method : public method_base
{
func m_func;
sqf::value val
public:
using func = T(*)(TArgs...);
method(func f) : m_func(f) {}
virtual retval can_call(std::vector<sqf::value> values) override
{
}
};
Appendix
If something is unclear, confusing or you just have further questions, please do ask them. I will try my best to rephrase whatever is unclear as this will help greatly with developing further extensions in the future, possibly defining a "go to" way for how to create extensions in the community for the game in question (Arma 3 just in case somebody wondered)
I may note that this is pretty much my first deep dive into meta programming so things I present may not be possible at all. If so, I kindly would like to ask you if you may also explain why that is so and the thing I attempt is not possible.
The Solution
I do want to express my thanks to all who answered this question again. I ended up combining pretty much parts of all solutions here and pretty much learned a lot on the way. The final implementation I ended up with looks like the following:
namespace meta
{
template <typename ArgType>
struct is_optional : std::false_type {};
template <typename T>
struct is_optional<std::optional<T>> : std::true_type {};
template <typename ArgType>
inline constexpr bool is_optional_v = is_optional<ArgType>::value;
template <typename ArgType>
struct def_value { static ArgType value() { return {}; } };
template <typename ArgType>
struct get_type { using type = ArgType; };
template <typename ArgType>
struct get_type<std::optional<ArgType>> { using type = ArgType; };
}
struct method {
std::function<bool(const std::vector<value>&)> m_can_call;
std::function<value(const std::vector<value>&)> m_call;
template <typename ... Args, std::size_t... IndexSequence>
static bool can_call_impl(const std::vector<value>& values, std::index_sequence<IndexSequence...> s) {
// values max args
return values.size() <= sizeof...(Args) &&
// for every Arg, either...
(... && (
// the value provides that argument and its the correct type, or...
(IndexSequence < values.size() && sqf::is<sqf::meta::get_type<Args>::type>(values[IndexSequence])) ||
// the value does not provide that argument and the arg is an optional
(IndexSequence >= values.size() && sqf::meta::is_optional_v<Args>)
));
}
template <typename Ret, typename ... Args, std::size_t... IndexSequence>
static value call_impl(std::function<Ret(Args...)> f, const std::vector<value>& values, std::index_sequence<IndexSequence...>) {
return {
// call the function with every type in the value set,
// padding with empty std::optionals otherwise
std::invoke(f,
(IndexSequence < values.size() ? sqf::get<sqf::meta::get_type<Args>::type>(values[IndexSequence])
: sqf::meta::def_value<Args>::value())...)
};
}
public:
template <typename Ret, typename ... Args>
method(std::function<Ret(Args...)> f) :
m_can_call([](const std::vector<value>& values) -> bool
{
return can_call_impl<Args...>(values, std::index_sequence_for<Args...>{});
}),
m_call([f](const std::vector<value>& values) -> value
{
return call_impl<Ret, Args...>(f, values, std::index_sequence_for<Args...>{});
})
{
}
bool can_call(const std::vector<value>& values) const { return m_can_call(values); }
value call_generic(const std::vector<value>& values) const { return m_call(values); }
// to handle lambda
template <typename F>
method static create(F f) { return method{ std::function{f} }; }
};
Assumming a way to check current type of value (template <typename T> bool value::isA<T>()) and a way to retrieve the value (template <typename T> /*const*/T& get(/*const*/ value&))
It seems you might do:
struct method
{
template <typename Ret, typename ... Ts>
method(std::function<Ret(Ts...)> f) : method(std::index_sequence<sizeof...(Ts)>(), f)
{}
template <typename Ret, typename ... Ts, std::size_t ... Is>
method(std::index_sequence<Is...>, std::function<Ret(Ts...)> f) :
isOk([](const std::vector<value>& values) {
return ((values.size() == sizeof...(Is)) && ... && values[Is].isA<Ts>());
}),
call([f](const std::vector<value>& values){
return f(get<Ts>(values[Is])...);
})
{}
// to handle lambda
template <typename F>
static fromCallable(F f) { return method{std::function{f}}; }
std::function<bool(const std::vector<value>&)> isOk;
std::function<value(const std::vector<value>&)> call;
};
Here's a quick example including the machinery for ret<T> and opt<T>. You haven't given any information on what value is, so I'm going to assume something like:
struct value {
// using `std::monostate` instead of `void`
std::variant<float, std::string, bool, std::vector<value>, std::monostate> data;
};
(I'm assuming c++17 for this answer.)
From there, we need our metatypes and a few traits to branch off them. I implement them using partial specialisations, but there are other ways too.
// types to determine optional vs. required
template <typename T>
struct req { using type = T; };
template <typename T>
struct opt { using type = T; };
// trait to determine if it's an optional type
template <typename ArgType>
struct is_optional : std::false_type {};
template <typename T>
struct is_optional<opt<T>> : std::true_type {};
template <typename ArgType>
inline constexpr bool is_optional_v = is_optional<ArgType>::value;
// get the "real" function parameter type
template <typename ArgType>
struct real_type;
template <typename ArgType>
using real_type_t = typename real_type<ArgType>::type;
template <typename T>
struct real_type<req<T>> { using type = T; };
template <typename T>
struct real_type<opt<T>> { using type = std::optional<T>; };
Now we implement method. I'll use a similar polymorphic relationship with method_base as you do in your partial demo; I also template on the function type passed in, to allow e.g. the functions to use const references to the type instead of the type itself.
The implementation itself uses the common trick of delegating to helper functions with std::index_sequence and fold expressions to "iterate" through the variadic template args.
// base class for polymorphism
struct method_base {
virtual ~method_base() = default;
virtual bool can_call(const std::vector<value>& values) const = 0;
virtual value call_generic(const std::vector<value>& values) const = 0;
};
// provide a different method implementation for each set of args
// I also overload on
template<typename RetType, typename Fn, typename... Args>
struct method : method_base {
private:
Fn func;
static_assert(std::is_invocable_r_v<RetType, Fn, real_type_t<Args>...>,
"function must be callable with given args");
public:
// accept any function that looks sort of like what we expect;
// static assert above makes sure it's sensible
template <typename G>
method(G&& func) : func(std::forward<G>(func)) {}
template <std::size_t... Is>
bool can_call_impl(const std::vector<value>& values, std::index_sequence<Is...>) const {
// for every Arg, either...
return (... and (
// the value provides that argument and its the correct type, or...
(Is < values.size() and std::holds_alternative<typename Args::type>(values[Is].data))
// the value does not provide that argument and the arg is an optional
or (Is >= values.size() and is_optional_v<Args>)
));
}
bool can_call(const std::vector<value>& values) const override {
return can_call_impl(values, std::index_sequence_for<Args...>{});
}
template <std::size_t... Is>
value call_generic_impl(const std::vector<value>& values, std::index_sequence<Is...>) const {
return {
// call the function with every type in the value set,
// padding with empty std::optionals otherwise
std::invoke(func,
(Is < values.size() ? std::get<typename Args::type>(values[Is].data)
: real_type_t<Args>{})...)
};
}
value call_generic(const std::vector<value>& values) const override {
return call_generic_impl(values, std::index_sequence_for<Args...>{});
}
};
I'll also create a helper function to make methods:
template <typename RetType, typename... Args, typename Fn>
std::unique_ptr<method_base> make_method(Fn&& func) {
return std::make_unique<method<RetType, std::decay_t<Fn>, Args...>>(std::forward<Fn>(func));
}
Live example.
It's not perfect, but this should give you a general idea of how to do it.
Change your method to:
method< R(Args...) >
your tags seem useless. Detect optional with ... std::optional.
For storage, use std variant. Use some non-void type for void (I don't care what).
As a first pass we aim for perfect compatibility.
template<class...Args>
struct check_signature {
bool operator()( std::span<value const> values ) const {
if (sizeof...(Args) != values.size()) return false;
std::size_t i=0;
return (std::holds_alternative<Args>(values[i++])&&...);
}
};
this can be stored in a std::function<bool(std::span<value const>)> or just called in your class impementation.
Similar code can store the callable.
template<class F, class R, class...Args>
struct execute {
F f;
template<std::size_t...Is>
R operator()( std::index_sequence<Is...>, std::span<value const> values ) const {
if (sizeof...(Args) != values.size()) return false;
return f( std::get<Args>(values[Is])... );
}
R operator()( std::span<value const> values ) const {
return (*this)( std::make_index_sequence<sizeof...(Args)>{}, values );
}
};
some work may have to be done for the fake void.
Your method is now a aggregate.
struct method {
std::function<bool(std::span<value const>)> can_call;
std::function<value(std::span<value const>)> execute;
};
if you want it to be. The two template objects above can be stored in these two std functions.
There are probably tpyos, I just wrote this on my phone and have not tested it.
Extending this to cover optional args is a little bit of work. But nothing hard.
In both cases, you'll write a helper function that says if the argument is compatible or generates the value based on if you are past the end of the incoming vector.
Ie, std::get<Args>(values[Is])... becomes getArgFrom<Is, Args>{}(values)..., and we specialize for std optional producing nullopt if Is>values.size().
Assume we have a class template like this:
template <typename baseT, typename ...argTs>
class CCallable : public baseT
{
public:
CCallable(std::function<bool(argTs...)> lambda)
: m_lambda(lambda) {
}
bool Invoke(argTs ...args) override {
return m_lambda(args...);
}
private:
std::function<bool(argTs...)> m_lambda;
};
And assume we have a function template callback implemented, probably similar to this pseudo code:
template <typename baseT, typename lambdaT>
CCallable<baseT, typename lambdaT::argTs...> callback(lambdaT lambda)
{
return CCallable<baseT, typename lambdaT::argTs...>(lambda);
}
so that we are able to do this:
auto&& functor = callback<CBase>([](int x, int y, int *sum)->bool{
*sum = x + y;
return true;
});
// Start passing functor around and then...
int sum;
functor.Invoke(7, 42, &sum);
Please note that the parameter types of the lambda are not passed to callback as its template type arguments.
How can we implement a function template like this, to save the users from typing more codes like:
auto&& functor = callback<CBase, int, int, int*>([](int x, int y, int *sum)->bool{
*sum = x + y;
return true;
});
Thanks.
By the way, why I'm asking this is because Microsoft::WRL provides a similar template named Callback which is called many times in an opensource library I want to use. However, I prefer to build the library with GNU C++ instead of Visual C++. Therefore, it seems inevitable that I have to implement a Microsoft::WRL::Callback-like template or macro myself.
With C++17 CTAD, you could harness deduction guides for std::function:
template<class T>
struct Identity { };
template<typename baseT, typename ...argTs>
class CCallable : public baseT {
public:
CCallable(std::function<bool(argTs...)> lambda, Identity<baseT> = {})
: m_lambda(lambda) {
}
bool Invoke(argTs ...args) override {
return m_lambda(args...);
}
private:
std::function<bool(argTs...)> m_lambda;
};
template<typename baseT, typename lambdaT>
auto callback(lambdaT lambda) {
return CCallable(std::function(lambda), Identity<baseT>{});
}
CTAD is all-or-nothing, so the type baseT is wrapped into Identity to make it deducible.
Demo
Hi I am trying to write a delegate class that can take a template argument similar to a standard function signature and create a delegate for a member function pointer as shown below in the main. The code may be oversimplified but that is what I was looking for was a simple and fast solution to this problem with as little overhead as possible. I think this implementation is pretty close to achieving what I want if I can get the type T in the class without runtime polymorphism etc.
template<class T>
struct FastDelegate {};
template<class R, class... Args>
struct FastDelegate<R (Args...)>
{
template <typename T>
FastDelegate(T* t, R (T::*f)(Args...)) : m_t(t), m_f(f) {}
R operator()(Args... p)
{
return (m_t->*m_f)(std::forward<Args>(p)...);
}
T* m_t; // How can I capture T as a type in this partial specialization?
R (T::*m_f)(Args...);
};
struct Test
{
int add ( int x, int y ) { return x+y; }
};
int main ()
{
int x = 5;
int y = 4;
Tester t;
FastDelegate<int (int,int)> d (&t, &Test::calc );
int z = d(x,y);
}
You could capture the objects as a void*, store the member function in random member function type, and have a function restore the necessary types. This approach avoid allocating any memory on the heap. The problematic step is the conversion from a member function of some type to another member function. However, according to 5.2.10 [expr.reinterpret.cast] paragraph 10 this approach can be used safely as long at the member function is cast back to its original type before being used:
[...] The result of this conversion is unspecified, except in the following cases:
converting a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.
Below is an example which implements this approach. Note, however, that it is probably easier to use std::function<R(Args...)> with a suitable lambda as the standard library is likely to implementation an approach like that in the first place.
#include <iostream>
#include <utility>
template<class T>
struct FastDelegate {};
template<class R, class... Args>
struct FastDelegate<R (Args...)>
{
struct dummy {};
template <typename T>
FastDelegate(T* t, R (T::*f)(Args...))
: m_t(t)
, m_f(reinterpret_cast<void (dummy::*)()>(f))
, m_call([](void(dummy::*d)(), void* v, Args... a){
typedef R (T::*mem)(Args...);
T* t = static_cast<T*>(v);
mem f = reinterpret_cast<mem>(d);
return (t->*f)(std::forward<Args>(a)...);
}) {
}
R operator()(Args... p) {
return (this->m_call)(this->m_f, this->m_t, std::forward<Args>(p)...);
}
void* m_t;
void (dummy::*m_f)();
R (*m_call)(void (dummy::*)(), void*, Args...);
};
struct Tester
{
int add ( int x, int y ) {
std::cout << "add(" << x << ", " << y << ")\n";
return x+y;
}
};
int main ()
{
int x = 5;
int y = 4;
Tester t;
FastDelegate<int (int,int)> d (&t, &Tester::add);
int z = d(x,y);
}
You don't need to capture type T, because you can use t->*m_f as a function<R(Args...)>
template<class R, class... Args>
struct FastDelegate<R (Args...)>
{
template <typename T>
FastDelegate(T* t, R (T::*f)(Args...))
: m_f([=](Args... v){ return (t->*f)(std::forward(v)...); }) {}
R operator()(Args... p)
{
return m_f(std::forward<Args>(p)...);
}
std::function<R(Args...)> m_f;
};
If you want to compare 2 FastDelegate instance by comparing t and f, there is still no need for type info, just take raw pointer.
Hi I was playing around with TMP and was thinking of generating of a class
that looks something like:
template<typename T, typename LogFunc>
class
{
(where LogFunc should be defaulted to "nop" function)
Idea is to have a class that defines some functionality for instances of type T, for example checks if the number is even, and also has the option to log by calling
void memberFunc(T& t)
{
LogFunc(t);
}
or maybe
void memberFunc(T& t)
{
LogFunc lf;
lf(t);
}
Can it be done?
From reading A on SO, lambdas are kind of problematic as templ params.
BTW if somebody cares this is what I tried but it prints out
:(
The problem is that the type of a lambda is a compiler-enforced singleton; it has only one value, which is the lambda itself; furthermore, the type has a deleted constructor. So you can't pass lambdas as part of a template instantiation, even with decltype. But there's nothing stopping you from passing them as constructor arguments.
However, here we run into another problem: constructor arguments are not used to deduce a template instantiation (which is why the standard library provides utilities like make_pair and make_tuple). So we need a templatized factory function.
With all that, the solution is pretty simple:
template<typename T, typename LogFunc>
class Foo {
public:
Foo(const T& t, LogFunc fn) : t_(t), lfn_(fn) {}
//...
private:
T t_;
LogFunc lfn_;
};
struct Noop {
template<typename...A>
void operator()(A...) { };
};
template<typename T, typename LogFunc=Noop>
Foo<T, LogFunc> make_foo(const T& t, LogFunc func=LogFunc()) {
return Foo<T, LogFunc>(t, func);
}
This will not answer directly, but gives a number of hints about what you did.
The LogFunc parameter is a type (not an object), hence
LogFunc(t) creates a temporary LogFunc giving t as parameter (you are in fact calling the LogFunc::LogFunc(T&) contructor).
LogFunc lf; lf(t); creates a stack-living default contructed Logfunc, named lf, and lf(t) calls its LogFunc::operator()(T&) member function.
LogFunc()(t) creates a temporary default-constructed LogFUnc and calls operator()(T&) on it.
About lambdas, they are in fact classes whose constructor takes the captured varaibles, and whose operator() takes the parameters you declare. But they exist only "internaly" to the compiler, and don't have a "name" you can refer to.
What you can do is deduce its type with a decltype, or with a free-function.
Typically a parametric functional class stores a frunction object, initialized at construction.
#include <iostream>
template<class Fn>
class LogFunc
{
public:
LogFunc(Fn f) :fn(f) {}
template<class T>
void memberFunc(T& t)
{ fn(t); }
private:
Fn fn;
};
template<class Fn>
LogFunc<Fn> makeLogFunc(Fn f)
{ return LogFunc<Fn>(f); }
int main()
{
int x=5;
auto lf = makeLogFunc([](int& a){ std::cout << a << std::endl; });
lf.memberFunc(x);
return 0;
}
compile as "g++ -pedantic -Wall -std=c++11", and will ouptut
5
The other answers are all fine, but you can also just pass in a constructor argument with a std::function<T>. That looks like this:
#include <functional>
#include <iostream>
template <typename T> void someOther(T val){
std::cout << "used other "<<val<<std::endl;
}
template <typename T> void noop(T val){
std::cout << "noop "<<val<<std::endl;
}
template<typename T>
struct A{
A(std::function<void(T)> f =noop<T> ) : mf(f){}
void memberFunc(T valx){
mf(valx);
}
std::function<void(T)> mf;
};
int main(){
A<int> aNoop; ;
A<float> aSomeOther{someOther<float>} ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}
An alternative is to use functor classes, like this:
#include <iostream>
template <typename T> struct OtherC{
void operator()(T v){ std::cout <<"other "<<v<<std::endl; };
};
template <typename T> struct NoopC{
void operator()(T){ std::cout << "noop"<<std::endl; };
};
template<typename T, template <typename X> class F = NoopC >
struct A{
static void memberFunc(T valx){ F<T>()(valx); }
};
int main(){
A<int> aNoop;
A<float,OtherC> aSomeOther ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}