C++ Compile-time polymorphism - c++

There two unrelated structures A and B
template <typename T>
struct A {};
template <typename T>
struct B {};
one enum type
typedef enum { ma, mb} M;
and class C containing function templates
class C
{
public:
template <typename T>
static void f1 ( A <T> &a) {}
template <typename T>
static void f2 ( B <T> &b) {}
template <typename U>
static void algo (U &u, M m)
{
/*Long algorithm here
....
*/
if ( m == ma) f1(u);
else f2(u);
}
};
Static method algo contains some algorithm, that is quite difficult... It modified some values and results into structure A or B.
I would like to run static method algo with objects A or B depending on M value. But how to say it to my compiler :-)
int main()
{
A <double> a;
C::algo (a, ma); //Error
}
Error 1 error C2784: 'void C::f1(A<T>)' : could not deduce template argument for 'A<T>' from 'B<T>
A] I was thinking about pointer to function, but they are not usable with function templates.
B] Maybe a compile polymorphism could help
template <typename U, M m>
static void algo (U &u, M <m> ) { ...} //Common for ma
template <typename U, M m>
static void algo (U &u, M <mb> ) { ...} //Spec. for mb
But this solution has one big problem: Both implementations should unnecessarily include almost the same code (why to write the algorithm twice?).
So I need one function algo() processing both types of arguments A and B. Is there any more comfortable solution?

It seems that you are using the enum to convey type information from the user. I would suggest that you don't.
In the simplest case if f1 and f2 are renamed f, then you can remove the if altogether and just call it. The compiler will call the appropriate overload for you.
If you cannot or don't want to rename the function templates, then you can write a helper template that will dispatch for you (basic class template undefined, specialisations for A and B that dispatch to the appropriate static function)
If the enum is used for something else (that the compiler cannot resolve for you), you can still pass it around and rewrite the helper to dispatch on the enum rather than the type of the argument and you will have to rewrite the code to have the enum value as a compile time constant (simplest: pass it as template argument to algo). In this case ou can write function specialisations instead of classes if you want, as they would be full specialisations. But note that if you can avoid having to pass it you will remove a whole family of errors: passing the wrong enum value.
// Remove the enum and rename the functions to be overloads:
//
struct C { // If everything is static, you might want to consider using a
// namespace rather than a class to bind the functions together...
// it will make life easier
template <typename T>
static void f( A<T> & ) { /* implement A version */ }
template <typename T>
static void f( B<T> & ) { /* implement B version */ }
template <typename T> // This T is either A<U> or B<U> for a given type U
static void algo( T & arg ) {
// common code
f( arg ); // compiler will pick up the appropriate template from above
}
};
For the other alternatives, it is easier if the enclosing scope is a namespace, but the idea would be the same (just might need to fight the syntax a bit harder:
template <typename T>
struct dispatcher;
template <typename T>
struct dispatcher< A<T> > {
static void f( A<T>& arg ) {
C::f1( arg );
}
};
template <typename T>
struct dispatcher< B<T> > {
static void f( B<T>& arg ) {
C::f2( arg );
}
};
template <typename T>
void C::algo( T & arg ) {
// common code
dispatcher<T>::f( arg );
}
Again, getting this to work with a class might be a bit trickier as it will probably need a couple of forward declarations, and I don't have a compiler at hand, but the sketch should lead you in the right direction.

Normal function overloading is sufficient:
template <typename T>
static void f1 ( A <T> &a) {}
template <typename T>
static void f2 ( B <T> &b) {}
template <typename T>
static void algo (A<T>& u) {
f1(u);
}
template <typename T>
static void algo (B<T>& u) {
f2(u);
}
And then:
A<int> a;
Foo::algo(a);
Although it's not clear what you stand to gain from such an arrangement.

If you realy need to do that in one function, you can use typetraits:
template<typename T, T Val>
struct value_type { static const T Value = Val; };
struct true_type : public value_type<bool, true>{};
struct false_type : public value_type<bool, false>{};
template<class T>
struct isClassA : public false_type{};
template<>
struct isClassA<A> : public true_type{};
template < typename T >
void Algo( T& rcT )
{
if ( true == isClassA<T>::Value )
{
// Class A algorithm
}
else
{
// Other algorithm
}
};

the value of m parameter is unknown until runtime, so the compiler has to generate code for both if (m == ma) and else branches when it specialize the function.
It then complains since it can't understand what he should do if you happen to call C::algo(a,mb) or similar.
As Jon suggested, overloading should fix your case, try using this code:
template<typename U>
static void f12(A<U>&u) { f1(u); }
template<typename U>
static void f12(B<U>&u) { f2(u); }
template<typename U>
static void algo(U& u, M m)
{
/* long algorithm here
...
*/
//use overloading to switch over U type instead of M value
f12(u);
}
Also you can use function pointers with template functions, as long as you specify the template parameters:
template<typename U>
static void algo(U& u, M m, void(*)(U&) func)
{
/* ... */
(*func)(u);
}
int main()
{
A <double> a;
C::algo (a, ma, &C::f1<double> );
}

Related

Passing std::vector of wrapper of std::variant into variadic class, wrapping variadic method without knowing the specifics

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().

Limit variable template to a list of types

I'm trying to modernise some GStreamer code by adding smart pointers. So for instance:
GstElement *pipeline = gst_pipeline_new("test-pipeline");
gst_object_unref(pipeline);
can be rewritten:
struct GstElementDeleter {
void operator()(GstElement* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GstElementDeleter> pipeline = gst_pipeline_new("test-pipeline");
But gst_object_unref() can be used on any gpointer so it can be rewritten:
template<typename T>
struct GPointerDeleter {
void operator()(T* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GPointerDeleter<GstElement>> pipeline = gst_pipeline_new("test-pipeline");
But what I'd like to do is limit this to only handling types that can be deallocated using gst_object_unref. Is there a way of declaring a template to only work with a list of types - GstElement, GstBus, etc?
Maybe you could make template the operator() (so there is no need to explicit the template parameter defining the smart pointer) and use SFINAE to enable the operator() only for the allowed types
struct GPointerDeleter
{
template <typename T>
typename std::enable_if<std::is_same<T, GstElement>::value
|| std::is_same<T, GstBus>::value
/* or other cases */
>::type operator() (T * p) const
{ gst_object_unref(p); }
};
Or, maybe better, you can add (as suggested by Jarod42 (thanks)) a static_assert() check inside the operator()
struct GPointerDeleter
{
template <typename T>
void operator() (T * p) const
{
static_assert( std::is_same<T, GstElement>::value
|| std::is_same<T, GstBus>::value
/* or other cases */, "some error message" );
gst_object_unref(p);
}
};
Perhaps a type trait? See <type_traits> if you haven't seen these before.
template<typename T>
struct can_gst_unref : std::false_type { };
// for each type...
template<> struct can_gst_unref<GstElement> : std::true_type { };
// convenient alias, as is convention for type traits
template<typename T>
inline constexpr bool can_gst_unref_v = can_gst_unref<T>::value;
// now conditionally define operator() in your deleter
struct GstDeleter {
template<typename T>
std::enable_if_t<can_gst_unref_v<T>> operator()(T* p) { gst_object_unref(p); }
};
// Making the function a template instead of the class reduces clutter at usage
std::unique_ptr<GstElement, GstDeleter> works(gst_pipeline_new("test-pipeline"));
// can_gst_unref is not specialized to std::string
// so the general case takes over, and gives can_gst_unref_v<std::string> = false
// std::enable_if_t thus doesn't produce a type, and operator() is not defined, because it has no return type
// therefore, this doesn't compile
std::unique_ptr<std::string, GstDeleter> whoops;

Detecting a function in C++ at compile time

Is there a way, presumably using templates, macros or a combination of the two, that I can generically apply a function to different classes of objects but have them respond in different ways if they do not have a specific function?
I specifically want to apply a function which will output the size of the object (i.e. the number of objects in a collection) if the object has that function but will output a simple replacement (such as "N/A") if the object doesn't. I.e.
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
I expect that this might be something similar to a static assertion although I'd clearly want to compile a different code path rather than fail at build stage.
From what I understand, you want to have a generic test to see if a class has a certain member function. This can be accomplished in C++ using SFINAE. In C++11 it's pretty simple, since you can use decltype:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
If you use C++03 it is a bit harder due to the lack of decltype, so you have to abuse sizeof instead:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Of course this uses Boost.Enable_If, which might be an unwanted (and unnecessary) dependency. However writing enable_if yourself is dead simple:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
In both cases the method signature test<U>(int) is only visible, if U has a size method, since otherwise evaluating either the decltype or the sizeof (depending on which version you use) will fail, which will then remove the method from consideration (due to SFINAE. The lengthy expressions std::declval<U>().size(), void(), std::true_type() is an abuse of C++ comma operator, which will return the last expression from the comma-separated list, so this makes sure the type is known as std::true_type for the C++11 variant (and the sizeof evaluates int for the C++03 variant). The void() in the middle is only there to make sure there are no strange overloads of the comma operator interfering with the evaluation.
Of course this will return true if T has a size method which is callable without arguments, but gives no guarantees about the return value. I assume wou probably want to detect only those methods which don't return void. This can be easily accomplished with a slight modification of the test(int) method:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
There was a discussion about the abilities of constexpr some times ago. It's time to use it I think :)
It is easy to design a trait with constexpr and decltype:
template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }
template <typename T>
constexpr bool has_size(...) { return false; }
So easy in fact that the trait loses most of its value:
#include <iostream>
#include <vector>
template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
std::cout << t.size() << "\n";
}
void print_size(...) { std::cout << "N/A\n"; }
int main() {
print_size(std::vector<int>{1, 2, 3});
print_size(1);
}
In action:
3
N/A
This can be done using a technique called SFINAE. In your specific case you could implement that using Boost.Concept Check. You'd have to write your own concept for checking for a size-method. Alternatively you could use an existing concept such as Container, which, among others, requires a size-method.
You can do something like
template< typename T>
int getSize(const T& t)
{
return -1;
}
template< typename T>
int getSize( const std::vector<T>& t)
{
return t.size();
}
template< typename T , typename U>
int getSize( const std::map<T,U>& t)
{
return t.size();
}
//Implement this interface for
//other objects
class ISupportsGetSize
{
public:
virtual int size() const= 0;
};
int getSize( const ISupportsGetSize & t )
{
return t.size();
}
int main()
{
int s = getSize( 4 );
std::vector<int> v;
s = getSize( v );
return 0;
}
basically the most generic implementation is always return -1 or "NA" but for vector and maps it will return the size. As the most general one always matches there is never a build time failure
Here you go. Replace std::cout with the output of your liking.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
You could try something like:
#include <iostream>
#include <vector>
template<typename T>
struct has_size
{
typedef char one;
typedef struct { char a[2]; } two;
template<typename Sig>
struct select
{
};
template<typename U>
static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0);
static two check (...);
static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0)));
};
struct A{ };
int main ( )
{
std::cout << has_size<int>::value << "\n";
std::cout << has_size<A>::value << "\n";
std::cout << has_size<std::vector<int>>::value << "\n";
}
but you have to be careful, this does neither work when size is overloaded, nor when it is a template. When you can use C++11, you can replace the above sizeof trick by decltype magic

Pointers to methods & templates problem, C++

There are 2 template classes A and B having 2 private members a1, a2 and b1, b2.
template <typename T>
class A
{
private:
T a1, a2;
public:
T getA1 () const {return a1;}
T getA2 () const {return a2;}
};
template <typename T>
class B
{
private:
T b1, b2;
public:
T getB1 () const {return b1;}
T getB2 () const {return b2;}
};
In the class Test there is a need for 2 pointers pointing to getters.
class Test
{
private:
template <typename T>
static T ( *getFirst ) ();
template <typename T>
static T ( *getSecond ) ();
}
template <typename T>
T ( * Test::getFirst ) () = &A<T>::getA1; //Pointer to getA1, error
template <typename T>
T ( * Test::getSecond ) () = &B<T>::getB2; //Pointer to getB2, error
int main
{
A <double> a;
B <double> b;
double c = a.getFirst + b.getSecond;
}
T represents fundamental data types... Is it possible implement this code without specialization (i.e. pointers to class template members) or those "pointers" should be specialized? Thanks for any examples...
You're doing illegal things. See this,
template <typename T>
static T ( *getFirst ) ();
Here you're trying to define template function pointer which is illegal in C++.
The C++ Standard says in $14/1,
A template defines a family of classes
or functions.
Please note that it does not say "a template defines a family of classes, functions or function pointers". So what you're trying to do is, defining "a family of function pointers" using template, which isn't allowed.
If you want function pointer you can do something like this,
template <class T>
struct A
{
static T (*FunctionPointer)(); //function pointer
};
struct B
{
template <class T>
static T Function(); //static function, not function pointer
};
int (*A<double>::FunctionPointer)() = &B::Function<double>;
Yet better alternative is : use function object. :-)
In short, it's not possible.
First, you cannot declare a pointer to template function, only pointer to a concrete function.
Second, you tried to declare pointer to free function but A::getA1 is a member function with implicit this argument, so semantic doesn't match.
You can do something like this:
template <typename T>
struct A
{
static T get() { return T() };
};
template <typename T>
struct Holder
{
typedef T(A<T>::*F_ptr)();
static F_ptr f_ptr;
};
template <typename T>
typename Holder<T>::F_ptr Holder<T>::f_ptr = &A<T>::get;
to keep pointer to template function as a member of template class
The line:
template <typename T>
T (*Test::getFirst)() = &A<T>::getA1; //Pointer to getA1, error
Has two problems: One is that &A<T>::getA1 is of type T (A::*)()const but getFirst is of type T (*)(). These are not compatible because the former is a pointer to a member function, while the latter is not.
The second problem with the line is that the objects created would differ only in their return type. Just like you cannot manually declare both double (A::*getFirst)()const and char (A::*getFirst)()const, you also cannot create a template that would automatically declare both of them.
The line:
double c = a.getFirst + b.getSecond;
Has its own set of problems that may or may not relate to the issue at hand.
Sorry for this "non answer." maybe if you talked more about what you are trying to accomplish, rather than how you are trying to accomplish it, we will be able to help.
Your code seems quite confused, so I'm not sure I really understood what you are asking for... here is an adaptation of your example that compiles.
// This is one template class A with two getters
template <typename T>
class A
{
private:
T a1, a2;
public:
T getA1 () const {return a1;}
T getA2 () const {return a2;}
};
// This is another unrelated template class, with two other getters
template <typename T>
class B
{
private:
T b1, b2;
public:
T getB1 () const {return b1;}
T getB2 () const {return b2;}
};
// These are declarations of generic "getFirst" and "getSecond"
template<typename T1, typename T2>
T1 getFirst(const T2& t);
template<class T1, class T2>
T1 getSecond(const T2& t);
// Here I'm specializing getFirst/getSecond for the A template
template<class X>
double getFirst(const A<X>& a) { return a.getA1(); }
template<class X>
double getSecond(const A<X>& a) { return a.getA2(); }
// Here I'm doing the same for the B template
template<class X>
double getFirst(const B<X>& b) { return b.getB1(); }
template<class X>
double getSecond(const B<X>& b) { return b.getB2(); }
// Now I can use getFirst/getSecond with either A or B
int main(int argc, const char *argv[])
{
A<double> a;
B<double> b;
double c = getFirst(a) + getSecond(b);
return 0;
}

Instantiating template with a variably modified type

One of my class' member method take as an argument of enumeration type: it produces different side effects for different enum. I was wondering whether it's possible to use template as a lookup table, two possible solutions came up to my mind, but none of them seems to work:
//// 1 ////
class A {
public:
enum AEnum : uint8_t { first, second, ... };
private:
template<AEnum N, typename T>
struct impl {
static void do_sth(T t) { ... };
};
template<typename T>
struct impl<first, T> {
static void do_sth(T t) { ... };
};
public:
template<typename T>
void do_sth(AEnum e, T t) {
impl<e, T>::do_sth(t);
}
}
//// 2 ////
class A {
public:
enum AEnum : uint8_t { first, second, ... };
private:
template<typename T_enum, typename T>
struct impl {
static void do_sth(T t) { ... };
};
template<typename T>
struct impl<uint8_t[2], T> { // A::first
static void do_sth(T t) { ... };
};
public:
template<typename T>
void do_sth(AEnum e, T t) {
impl<uint8_t[static_cast<uint8_t>(e) + 1u], T>::do_sth(t);
}
}
Is it really bad idea to code it this way?
#Oli Charlesworth
What's wrong with a switch statement?
Supported types of do_sth's second argument (T) varies with value of e, e.g. A::first supports integrals, and A::second STL containers, e.g.:
template<typename T>
void do_sth(AEnum e, T t) {
switch(e) {
case first:
std::cout << &t << std::endl;
break;
case second:
std::cout << t.data() << std::endl;
break;
default:
break;
}
A a;
a.do_sth(A::first, 0);
You have to make the AEnum arg a template argument to do_sth:
template<AEnum e, typename T>
void do_sth(T t) { ... }
...and call it as a.do_sth<A::first>(0).
Alternatively, you could write separate functions (do_sth_integral, do_sth_container, ...), or, if there is only one correct course of action for a particular T, deduce the "correct" enum value for a given T using metaprogramming/overloading tricks.
For example, here's a way of writing two functions that e.g. detect numeric types and container types:
//The extra dummy argument is invalid for types without a nested
//"iterator" typedef
template<typename T>
void do_sth(T t, typename T::iterator * = 0)
{
//container type code
}
//The dummy arg is invalid for types without a
//std::numeric_limits specialization
template<typename T>
void do_sth(T t,
typename boost::enable_if_c<std::numeric_limits<T>::is_specialized>::type * = 0)
{
//numeric type code
}
Of course, this would fail if you passed a T which has an iterator typedef and a numeric_limits specialization, or has neither.
If there is only one sensible action for a particular T, and it's hard to correctly guess which overload should be used for an unknown T, then you could use a traits class that users have to specialize explicitly, or just require that users specialize an "impl" or dispatching class.
You can't write a function that does something like 3.data(), even if that code path is never called when the program runs. The compiler doesn't know that it will never be called, and in any case, it violates the type system of the language in a way that is required to cause a diagnosed error.
Yes, what you've coded doesn't make any sense. Template instantiations are resolved at compiler-time, whereas obviously the value of e is only known at run-time.
What's wrong with a switch statement?