How do you specialize a member function inside a template class? - c++

Let's say I have the following class:
template <typename T>
class SomeClass : Parent<T>
{
public:
// I have a function such as this one:
T DoSomething(const T &t)
{
return t.DoSomething(some_data);
}
// But `T` might be a pointer, so sometimes I will need something like the following
// instead (which obviously doesn't work as given):
T DoSomething(const T &t)
{
return new T(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
I got stuck in a giant mess of template errors trying to implement this in any semi-nice way possible using template specialization.
In the end I came up with this very ugly solution:
template <typename T>
class SomeClass : Parent<T>
{
public:
T DoSomething(const T &x)
{
return Specializer<T>::Do(this, x);
}
private:
template <typename V>
struct Specializer {
static V Do(SomeClass *me, const V &x)
{
return x.DoSomething(me->some_data);
}
};
template <typename V>
struct Specializer<V*> {
static V* Do(SomeClass *me, const V *&x)
{
return new V(x->DoSomething(me->some_data));
}
};
XYZ some_data;
};
Is there a better way to do this that doesn't involve stuffing this function into a dummy class/struct and passing around my this pointer?
PS: In reality, this has nothing to do with pointers, but rather with different types of containers. Pointers were just an easy example to use here.

You can avoid writing any specializations, and use a type trait like std::is_pointer along with if constexpr to decide what code to execute depending on the whether the type is a pointer type or not:
auto DoSomething(const T &t)
{
if constexpr (std::is_pointer_v<T>)
return new T(t->DoSomething(some_data));
else
return t.DoSomething(some_data);
}
If you don't want to check for whether T is a pointer, but want to check something else, you can still use this pattern by dropping in a suitable replacement for is_pointer.

If you have access to c++20, you can clean up the need for any SFINAE, specializations, or if constexpr by using concepts and constraints instead. This just allows you to define the same function N times with different criteria for its insantiation, which is much more readable IMO.
This is almost the same as the SFINAE approach, but without the need for the awful syntax (no std::declval, decltype, etc). It also doesn't require all implementations to exist in one function definition like the if constexpr approach; all you need is separate function definitions with different requires clauses:
#include <concepts>
...
template <typename T>
class SomeClass : Parent<T>
{
public:
// Work for everything that's not specialized
void DoSomething(const T &t)
{
std::cout << "Basic overload" << std::endl;
}
// Only work for pointers
void DoSomething(const T& t) requires(std::is_pointer_v<T>)
{
std::cout << "Pointer overload" << std::endl;
}
// Only work if T is convertible to SomeType
void DoSomething(const T& t) requires(std::convertible_to<T, SomeType>)
{
std::cout << "Convertible to SomeType overload" << std::endl;
}
private:
XYZ some_data;
};
Live Example
In this approach there are 3 different entries:
The basic fallback for all templates
An implementation that works for any pointer type, and
An implementation that works for any T type that may be convertible to SomeType

What about using SFINAE?
For example
#include <utility>
#include <iostream>
template <typename>
struct Parent
{ };
using XYZ = int;
template <typename T>
class SomeClass : Parent<T>
{
public:
template <typename U = T>
auto DoSomething (T const & t)
-> decltype( std::declval<U>().DoSomething(std::declval<XYZ>()) )
{ std::cout << "ref\n"; return t.DoSomething(some_data); }
template <typename U = T>
auto DoSomething (T const & t)
-> std::remove_reference_t<
decltype( std::declval<U>()->DoSomething(std::declval<XYZ>()),
std::declval<T>() )>
{
using V = std::remove_reference_t<decltype(*t)>;
std::cout << "pnt\n"; return new V(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
struct foo
{
foo (foo*) {}
foo () {}
foo DoSomething (int) const { return {}; }
} ;
int main()
{
SomeClass<foo> sc1;
SomeClass<foo*> sc2;
foo f;
sc1.DoSomething(f);
sc2.DoSomething(&f);
}
I mean: what about enabling the first version if, and only if, T is a type that supports a DoSomething(XYZ) method and enabling the second version if, and only if, T is a pointer of a type that supports a DoSomething(XYZ) method?

Related

How to identify if a method of underlying type held by a shared_ptr can be invoked with one or no parameters at compile time

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

How to make a C++ templated function agnostic to the return type for future specialization

I would like to have a general templated function declaration for which I do not know (already) the return type, similar to:
**template <class T> auto getIds() noexcept -> std::vector<Any>;**
The function could then be specialized with several input types, and a return type based on it:
template <> auto getIds<MyClass>() noexcept -> std::vector<decltype(MyClass::id)>
{
// implementation here.
}
And finally call it without to set the return:
auto val = getIds<MyClass>();
Is that possible? How?
Notes:
What I want to avoid is to have to set manually the Id type in the call function:
auto val = getIds<MyClass, decltype(MyClass::id)>(); // Ugly
I also discard any (non based on template) solution like extending all types from a RootMyClass. Is not that these solutions are bad, but they miss the point of this question.
Trying to be a bit clearer:
If I wrote
class MyClass { public: int id1=4;};
template <class T, class Id> auto getIds() -> Id;
template <> auto getIds<MyClass, decltype(MyClass::id1)>() -> decltype(MyClass::id1)
{
return 1;
}
auto main() -> int
{
getIds<MyClass>(); // Do not compile
getIds<MyClass, decltype(MyClass::id1)>(); // Compile but ugly
}
I would like the return type to be implicit, but I did not found a way to achieve that with specializations:
template <class T> getIds() noexcept -> WHICH TYPE?;
You cannot change the return type in a specialization, unfortunately. What you can do is change the return type in different overloads. Obviously. Furthermore, function template specializations are much more complicated than function overloads anyway, so let's do that.
Introduce an empty type wrapper, say:
template <typename T> struct wrapper { };
And forward the default implementation to that (I'm assuming C++14 here, otherwise you could wrap that in decltype() with a trailing return):
template <typename T>
auto getIds() { return getIds(wrapper<T>{}); }
Declare the generic version as:
template <typename T>
void getIds(wrapper<T> );
Don't define it. Then, anytime somebody tries to do:
auto ids = getIds<X>();
If there is no overload, that will simply fail to compile as you cannot assign from void. Then, you can overload as you see fit:
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{ ... }
FINAL EXAMPLE:
#include <iostream>
#include <vector>
template <typename T> struct wrapper { };
template <typename T>
auto getIds() -> decltype(getIds(wrapper<T>{}))
{
return getIds(wrapper<T>{});
}
template <typename T>
void getIds(wrapper<T> ) { }
struct MyClass {
int id;
};
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{
return {1, 2, 3};
}
int main()
{
for (auto id : getIds<MyClass>()) {
std::cout << id << " ";
}
}
This is actually very similar to Haskell typeclasses, and, surprisingly, works. For real usage I would use functors to allow partial specializations, though.
#include <iostream>
template<typename T>
decltype(T::x) getX(T const& t) { return; }
class A { public: int x; A(int x):x(x){} };
template<> int getX<A>(A const& a) {
return a.x;
}
class B { public: std::string x; B(std::string x):x(std::move(x)){} };
template<> std::string getX<B>(B const& b) {
return b.x;
}
int main() {
A a(42);
B b("43");
std::cout << getX(a) << std::endl;
std::cout << getX(b) << std::endl;
}
As you can see, each specialization has to (can?) provide the return type explicitly. decltype(A::x) (and B::x), respectively) could be used instead if you so prefer.
To make it even more Haskell-ish, you could expect a type tag in the type itself (basically a type family):
template<typename T>
typename T::TypeOfX getX(T const& t) { return; }
And consequently:
class A {
using TypeOfX = int;
TypeOfX someComplexLogicToGetX();
};
Both solutions to the type being instantiated for the actual type, except one gets it from a type of a field, and the other from a direct "type variable".

Determining inheritance relationships among type-erased classes

I have a typical type-erasure setup:
struct TEBase
{
virtual ~TEBase() {}
// ...
};
template <typename T>
struct TEImpl : TEBase
{
// ...
};
Now the question: Given a second class hierarchy like this,
struct Foo { };
struct Bar : Foo { };
struct Unrelated { };
is it possible, given a TEBase * p, to determine whether the dynamic type of *p is of the form TEImpl<X>, where, X derives from Foo? In other words, I want function:
template <typename T> bool is_derived_from(TEBase * p);
such that:
is_derived_from<Foo>(new TEImpl<Foo>) == true
is_derived_from<Foo>(new TEImpl<Bar>) == true
is_derived_from<Foo>(new TEImpl<Unrelated>) == false
In particular, I'm looking for a solution that is general, non-intrusive, and efficient. I've found two solutions to this problem (posted below as answers) but neither of them solve all three criteria.
Something like this:
template <typename Type, typename UnaryPredicate>
void DoPred(UnaryPredicate pred)
{
if (T * p = dynamic_cast<Derived<T> *>(this))
{
return pred(p->type);
}
return false;
}
This isn't 100% universal, since you cannot, for example, say DoPred<int>. A more universal solution would add a virtual std::type_info type() const { return typeid(...); } member function to the hierarchy and use that to determine if the type matches (the standard type erasure idiom). Both approaches use the same sort of RTTI, though.
After the clarification:
Right now, I don't think this can be solved. All you have is a TEBase subobject. It could be part of a TEImpl<Bar>, or part of a TEImpl<Unrelated>, but neither of those types is related to TEImpl<Foo>, which is what you're after.
You're essentially asking that TEImpl<Bar> derives from TEImpl<Foo>. To do this, you would actually want TEImpl<T> to inherit from all TEImpl<std::direct_bases<T>::type>..., if you see what I mean. This is not possible in C++11, but will be possible in TR2. GCC already supports it. Here is an example implementation. (It causes a warning due to ambiguous bases, which could be avoided with more work, but it works nonetheless.)
#include <tr2/type_traits>
struct TEBase { virtual ~TEBase() {} };
template <typename T> struct TEImpl;
template <typename TL> struct Derivator;
template <typename TL, bool EmptyTL>
struct DerivatorImpl;
template <typename TL>
struct DerivatorImpl<TL, true>
: TEBase
{ };
template <typename TL>
struct DerivatorImpl<TL, false>
: TEImpl<typename TL::first::type>
, Derivator<typename TL::rest::type>
{ };
template <typename TL>
struct Derivator
: DerivatorImpl<TL, TL::empty::value>
{ };
template <typename T>
struct TEImpl
: Derivator<typename std::tr2::direct_bases<T>::type>
{
};
template <typename T>
bool is(TEBase const * b)
{
return nullptr != dynamic_cast<TEImpl<T> const *>(b);
}
struct Foo {};
struct Bar : Foo {};
struct Unrelated {};
#include <iostream>
#include <iomanip>
int main()
{
TEImpl<int> x;
TEImpl<Unrelated> y;
TEImpl<Bar> z;
TEImpl<Foo> c;
std::cout << std::boolalpha << "int ?< Foo: " << is<Foo>(&x) << "\n";
std::cout << std::boolalpha << "Unr ?< Foo: " << is<Foo>(&y) << "\n";
std::cout << std::boolalpha << "Bar ?< Foo: " << is<Foo>(&z) << "\n";
std::cout << std::boolalpha << "Foo ?< Foo: " << is<Foo>(&c) << "\n";
}
I would suggest reading the article Generic Programming:Typelists and Applications. There Andrei Alexandrescu desribes an implementation of a ad-hoc Visitor which should solve your problem. Another good resource would be his book Moder C++ Design where he describes a multidispatcher in a Brute Force way which uses the same approuch (pages 265 ...).
In my opinion these 2 resources are better for understanding than any code which could be printed here.
This solution involves abusing exceptions a bit. If the TEImpl type simply throws its data, is_derived_from can catch the type it's looking for.
struct TEBase
{
virtual ~TEBase() {}
virtual void throw_data() = 0;
};
template <typename T>
struct TEImpl : public TEBase
{
void throw_data() {
throw &data;
}
T data;
};
template <typename T>
bool is_derived_from(TEBase* p)
{
try {
p->throw_data();
} catch (T*) {
return true;
} catch (...) {
// Do nothing
}
return false;
}
This solution works great. It works perfectly with any inheritance structure, and it's completely non-intrusive.
The only problem is that it's no efficient at all. Exceptions were not intended to be used in this way, and I suspect this solution is thousands of times slower than other solutions.
This solution involves comparing typeids. TEImpl knows its own type, so it can check a passed typeid against its own.
The trouble is, this technique doesn't work when you add inheritance, so I'm also using template meta-programming to check if the type has typedef super defined, in which case it will recursively check its parent class.
struct TEBase
{
virtual ~TEBase() {}
virtual bool is_type(const type_info& ti) = 0;
};
template <typename T>
struct TEImpl : public TEBase
{
bool is_type(const type_info& ti) {
return is_type_impl<T>(ti);
}
template <typename Haystack>
static bool is_type_impl(const type_info& ti) {
return is_type_super<Haystack>(ti, nullptr);
}
template <typename Haystack>
static bool is_type_super(const type_info& ti, typename Haystack::super*) {
if(typeid( Haystack ) == ti) return true;
return is_type_impl<typename Haystack::super>(ti);
}
template <typename Haystack>
static bool is_type_super(const type_info& ti, ...) {
return typeid(Haystack) == ti;
}
};
template <typename T>
bool is_derived_from(TEBase* p)
{
return p->is_type(typeid( T ));
}
For this to work with, Bar needs to be redefined as:
struct Bar : public Foo
{
typedef Foo super;
};
This should be fairly efficient, but it's obviously not non-intrusive, since it requires a typedef super in the target class whenever inheritance is being used. The typedef super also has to be publicly accessible, which goes against what many consider to be a recommended practice of putting your typedef super in your private section.
It also doesn't deal with multiple-inheritance at all.
Update: This solution can be taken further to make it general and non-intrusive.
Making it general
typedef super is great, because it's idiomatic and already used in many classes, but it doesn't allow multiple inheritance. In order to do that, we'll need to replace it with a type that can store multiple types, such as a tuple.
If Bar was rewritten as:
struct Bar : public Foo, public Baz
{
typedef tuple<Foo, Baz> supers;
};
we could support this form of declaration by adding the following code to TEImpl:
template <typename Haystack>
static bool is_type_impl(const type_info& ti) {
// Redefined to call is_type_supers instead of is_type_super
return is_type_supers<Haystack>(ti, nullptr);
}
template <typename Haystack>
static bool is_type_supers(const type_info& ti, typename Haystack::supers*) {
return IsTypeTuple<typename Haystack::supers, tuple_size<typename Haystack::supers>::value>::match(ti);
}
template <typename Haystack>
static bool is_type_supers(const type_info& ti, ...) {
return is_type_super<Haystack>(ti, nullptr);
}
template <typename Haystack, size_t N>
struct IsTypeTuple
{
static bool match(const type_info& ti) {
if(is_type_impl<typename tuple_element< N-1, Haystack >::type>( ti )) return true;
return IsTypeTuple<Haystack, N-1>::match(ti);
}
};
template <typename Haystack>
struct IsTypeTuple<Haystack, 0>
{
static bool match(const type_info& ti) { return false; }
};
Making it non-intrusive
Now we have a solution which is efficient and general, but it's still intrusive, so it won't support classes that can't be modified.
To support this, we'll need a way to declare the object inheritance from outside the class. For Foo, we could do something like this:
template <>
struct ClassHierarchy<Bar>
{
typedef tuple<Foo, Baz> supers;
};
To support that style, first we need the non-specialized form of ClassHierarchy, which we'll define like so:
template <typename T> struct ClassHierarchy { typedef bool undefined; };
We'll use the presence of undefined to tell whether or not the class has been specialized.
Now we need to add some more functions to TEImpl. We'll still reuse most of the code from earlier, but now we'll also support reading the type data from ClassHierarchy.
template <typename Haystack>
static bool is_type_impl(const type_info& ti) {
// Redefined to call is_type_external instead of is_type_supers.
return is_type_external<Haystack>(ti, nullptr);
}
template <typename Haystack>
static bool is_type_external(const type_info& ti, typename ClassHierarchy<Haystack>::undefined*) {
return is_type_supers<Haystack>(ti, nullptr);
}
template <typename Haystack>
static bool is_type_external(const type_info& ti, ...) {
return is_type_supers<ClassHierarchy< Haystack >>(ti, nullptr);
}
template <typename Haystack>
struct ActualType
{
typedef Haystack type;
};
template <typename Haystack>
struct ActualType<ClassHierarchy< Haystack >>
{
typedef Haystack type;
};
template <typename Haystack>
static bool is_type_super(const type_info& ti, ...) {
// Redefined to reference ActualType
return typeid(typename ActualType<Haystack>::type) == ti;
}
And now we have a solution which is efficient, general, and non-intrusive.
Future solution
This solution meets the criteria, but it's still a little annoying to have to document the class hierarchy explicitly. The compiler already knows everything about the class hierarchy, so it's a shame that we have to do this grunt work.
A proposed solution to this problem is N2965: Type traits and base classes, which has been implemented in GCC. This paper defines a direct_bases class, which is almost identical to our ClassHierarchy class, except its only element, type, is guaranteed to be a tuple, like supers, and the class is completely generated by the compiler.
So for now we have to write a little boilerplate to get this to work, but if N2965 gets accepted, we can get rid of the boilerplate and make TEImpl much shorter.
Special thanks to Kerrek SB and Jan Herrmann. This answer drew a lot of inspiration from their comments.

How to determine whether the template type is a basic type or a class

I have code something like this
template <typename T> void fun (T value)
{
.....
value.print (); //Here if T is a class I want to call print (),
//otherwise use printf
.....
}
Now, to print the value, if T is a class, I want to call the print function of the object, but if T is a basic datatype, I just want to use printf.
So, how do I find if the Template type is a basic data type or a class?
You could use std::is_class (and possibly std::is_union). The details depend on your definition of "basic type". See more on type support here.
But note that in C++ one usually overloads std::ostream& operator<<(std::ostream&, T) for printing user defined types T. This way, you do not need to worry about whether the type passed to your function template is a class or not:
template <typename T> void fun (T value)
{
std::cout << value << "\n";
}
Recommend overloading operator<<(std::ostream&) for any type T instead of using printf(): how would you know what format specifier to use?
template <typename T> void fun (T value)
{
.....
std::cout << value << std::endl;
.....
}
FWIW, std::is_class exists.
If you don't have C++11 support, an alternative.
template<typename T>
class isClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(…);
public:
enum { Yes = sizeof(isClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};
A simple template for finding out if type is class type. More in C++ Templates a Complete Guide.
if (isClassT<T>::Yes) {
std::cout << " Type is class " << std::endl;
}
I'd go with a printing helper function template/overload:
template <typename T>
void print(T const & t) { t.print(); }
template <typename U>
void print(U * p) { std::printf("%p", static_cast<void*>(p)); }
// we really an enable_if on is_object<U>::value here...
void print(char x) { std::printf("%c", x); }
void print(int x) { std::printf("%d", x); }
// etc. for all fundamental types
Then you can simply say print(value); in your code.

How to have std::function or lambda as (optional) template parameter?

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);
}