compiling with GCC i get always false from the following code. I believe this is a compiler bug, but someone may know better.
#include <iostream>
template< class T >
class has_apply {
typedef char yes[1];
typedef char no[2];
template< class U, U u >
struct binder {};
template< class U, unsigned n >
static yes& test( U*,
binder< void (U::*) ( const double& ),
&U::template apply< n >
>* = 0
);
template< class U, unsigned n >
static no& test( ... );
public:
static const bool result =
( sizeof( yes ) == sizeof( test< T, 0u >( (T*)(0) ) ) );
};
class A {
public:
template< unsigned n >
void apply( const double& );
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
return( 0 );
}
I can't claim to understand why, but I was able to make your code work by not taking U* and by pulling the declaration of the binder type out:
template< class T >
class has_apply {
public:
typedef char yes[1];
typedef char no[2];
template< class U, U u >
struct binder {};
typedef binder< void (T::*)(const double&), &T::template apply<0u> > b;
template < typename V, unsigned n >
struct declare
{
typedef binder< void (V::*)(const double&), &V::template apply<n> > type;
};
template< typename U, unsigned n >
static yes& test( typename declare<U,n>::type * );
template< class U, unsigned n >
static no& test( ... );
static const bool result =
( sizeof( yes ) == sizeof( test< T, 0u >( 0 ) ) );
};
You can actually simplify this a bit by removing the unsigned parameter from the function and just sticking 0u in the typedef within 'declare'.
Again, I can't explain why this intermediate metafunction is necessary but it was required and the above works in MSVC++ 2010
Andy Venikov's answer over in [comp.lang.c++.moderated] (I'm only taking credit for great google-foo (he he, I cheated)):
http://groups.google.com/group/comp.lang.c++.moderated/msg/93017cf706e08c9e
Like Noah I don't know why. Unlike Noah I didn't find a workable solution, but investigating the thing I managed to crash the MingW g++ 4.4.1 compiler (that is, an Internal Compiler Error). This was simply by inconsistently referring to apply as template and non-template:
#include <iostream>
template< class T >
class has_apply {
template< class U, U u >
struct binder {};
template< class U >
static double test(
U*,
binder<
void (U::*) ( const double& ),
//&U::template apply< 0 >
&U::apply
>* = 0
);
public:
static binder<
void (T::*) ( const double& ),
&T::template apply< 0 >
>* dummy();
static const bool result = sizeof( test( (T*)(0), dummy() ) );
};
class A {
public:
// template< unsigned n >
void apply( const double& );
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
return( 0 );
}
Effect on g++:
C:\test> g++ -std=c++98 y.cpp
y.cpp: In instantiation of 'has_apply':
y.cpp:38: instantiated from here
y.cpp:24: internal compiler error: in instantiate_type, at cp/class.c:6303
Please submit a full bug report,
with preprocessed source if appropriate.
See for instructions.
C:\test> _
He he...
PS: I'd love to post this as a "comment", since it's not an "answer".
This is not an answer to why it doesn't work. However, researching through the web, I've found some examples and eventually got to the following code, which may be even more to the point then what I've been trying.
I was trying to detect an specific member function signature, but the code below goes beyond and detects whether a given call is possible, no matter what is the signature. Hope the comments will be helpful.
#include <iostream>
template< class T >
class has_apply {
class yes { char c; };
class no { yes c[2]; };
struct mixin {
void apply( void );
};
// Calling derived::apply is only non-ambiguous if
// T::apply does not exist, cf. 10.2.2.
template< class U> struct derived : public U, public mixin {};
// The following template will help on deduction based on this fact.
// If U is type void (mixin::*) (void) then the template can be
// instantiated with u = &derived< U >::apply if and only if T::apply
// does not exist.
template< class U, U u >
class binder {};
// Therefore, the following template function is only selected if there
// is no T::apply:
template< class U >
static no deduce( U, binder< void (mixin::*) (void), &derived< U >::apply >* = 0 );
// Selected otherwise.
static yes deduce( ... );
// Provides an T object:
static T T_obj( void );
public:
static const bool result = ( sizeof( yes ) == sizeof( deduce( T_obj() ) ) );
};
namespace aux {
// Class to represent the void type as a "true" type.
class void_type {};
// deduce() some lines below will give us the right answer based on
// the return type of T::apply<>, but if it is void we cannot use a
// call to T::apply as an argument to deduce. In fact, the only
// function in c++ that can take such an argument is operator,() with
// its default behaviour and if an overload is not well formed it
// falls back to default.
template< class T >
T& operator,( const T&, void_type ) {};
// Copies the constness of T into U. This will be required in order
// to not get false positives when no const member is defined.
template< class T, class U >
struct copy_constness {
typedef U result;
};
template< class T, class U >
struct copy_constness< const T, U > {
typedef const U result;
};
}
template< class T >
class has_correct_apply{
class yes { char c; };
class no { yes c[2]; };
// We assume has_apply< T >::result is true so the following class
// is well declared. It is declared in a way such that a call to
// derived::apply< n >() is always possible. This will be necessary
// later.
struct derived : public T {
using T::apply; // possible iff has_apply< T >::result == true
// This template function will be selected if the function call
// we wish is otherwise invalid.
template< unsigned n >
static no apply( ... );
};
// const_correct_derived will have the same constness than T.
typedef typename aux::copy_constness< T, derived >::result const_correct_derived;
// Provides a const correct derived object.
static const_correct_derived derived_obj( void );
// Only possible call was derived::apply: call is impossible for signature:
static no deduce( no );
// Since te returned value of it will most likely be
// ignored in our code (void must be always [almost, see next]
// ignored anyway), we return yes from this:
static yes deduce( ... );
// As we noticed, an overload of operator,() may make an exact match necessary.
// If we want this we could simply have used "no" instead of "yes" above and:
// static no deduce( aux::void_type );
public:
static const bool result = ( sizeof( yes ) == sizeof( deduce(
( derived_obj().template apply< 0u >( 0.0 ), aux::void_type() )
) ) );
// Note: Inteestingly enough, GCC does not detect an private subclass default
// constructor and so const_correct_derived() could be used instead of
// having a function derived_obj(), but I do not know if this behavoiur is
// standard or not.
};
struct C {
template< unsigned n >
int apply( double, unsigned m = 10 ) const;
private:
C();
};
struct D {
template< unsigned n >
int apply( const double& );
private:
D();
};
struct E : public C {
};
struct Without{};
#include "mp.h"
int main()
{
std::cout << has_apply< E >::result << '\n';
std::cout << has_correct_apply< const E >::result << '\n';
std::cout << has_correct_apply< const D >::result << '\n';
std::cout << has_correct_apply< D >::result << '\n';
// E e;
return( 0 );
}
Related
There is a nice question (Which substitution failures are not allowed in requires clauses?) proposing the next problem.
One needs to write a compile-time function template<typename... Ts> constexpr bool allTypesUnique() that will return true if all argument types are unique, and false otherwise. And the restriction is not to compare the argument types pairwise. Unfortunately, the answer only explains why such function cannot be implemented with some particular approach.
I think the solution can be achieved using multiple inheritance. The idea is to make a class inherited from a number of classes: one for each type T in Ts. And each such class defines a virtual function with a signature depending on T. If some T is found more than once in Ts then function f in a child class will override the function in a base class and it can be detected:
template<typename> struct A{};
template<typename T, typename... Ts>
struct B : B<Ts...> {
using B<Ts...>::f;
constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
int count = 0;
};
template<typename T>
struct B<T> {
constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
int count = 0;
};
template<typename... Ts>
constexpr bool allTypesUnique() {
B<Ts...> b;
bool res = true;
( b.f( A<Ts>{}, res ), ... );
return res;
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int&>() );
static_assert( !allTypesUnique<int&, int&>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo: https://gcc.godbolt.org/z/8jhnE7P11
Just curious, is the solution correct and is there a simpler solution for this problem?
A simpler solution can be obtained in compilers supporting class size optimization via C++20 attribute [[no_unique_address]] for empty members. If all class empty members have distinct types, then its sizeof will be 1. If some member types are repeating then they cannot share the same address and sizeof will be more than 1.
Solution code:
template<typename> struct A{};
template<typename T, typename... Ts>
struct B : B<Ts...> {
[[no_unique_address]] A<T> a;
};
template<typename T>
struct B<T> {
[[no_unique_address]] A<T> a;
};
template<typename... Ts>
constexpr bool allTypesUnique() {
if constexpr (sizeof...(Ts) <= 1 )
return true;
else
return sizeof(B<Ts...>) == 1;
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int&>() );
static_assert( !allTypesUnique<int&, int&>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo: https://gcc.godbolt.org/z/577EP1774
A single constexpr function can be constructed to answer this question:
template <class T, class... Ts>
constexpr bool unique_types()
{
if constexpr (sizeof...(Ts)) {
return !(std::is_same_v<T,Ts> || ...) && unique_types<Ts...>();
}
return true;
}
Demo
the code above is the compile time equivalent of
for (int i(0); i < n; ++i)
for (int j(i + 1); j < n; ++j)
{ /* check type[i] vs type[j] */ }
If you want any variation in comparison (e.g. consider int same as int&) just modify the std::is_same_v (e.g. std::is_same_v<std::decay_t<T>, std::decay_t<Ts>>)
If you use virtual base classes depending on each of the given types, you will get exact one base class instance for every unique type in the resulting class. If the number of given types is the number of generated base classes, each type was unique. You can "measure" the number of generated base classes by its size but must take care that you have a vtable pointer inside which size is implementation dependent. As this, each generated type should be big enough to hide alignment problems.
BTW: It works also for reference types.
template < typename T> struct AnyT { char i[128]; };
template < typename FIRST, typename ... T>
struct CheckT: virtual AnyT<FIRST>, virtual CheckT<T...> { };
template < typename FIRST >
struct CheckT<FIRST>: virtual AnyT<FIRST> {};
template < typename ... T>
constexpr bool allTypesUnique()
{
using T1 = CheckT<int>;
using T2 = CheckT<bool, int>;
constexpr std::size_t s1 = sizeof( T1 );
constexpr std::size_t s2 = sizeof( T2 );
constexpr std::size_t diff = s2 - s1;
constexpr std::size_t base = s1 - diff;
constexpr std::size_t measure = sizeof( CheckT< T...> );
return !((sizeof...(T)*diff+base) - measure);
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int>() );
static_assert( !allTypesUnique<void, void>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo
I think you can try to elaborate on using compile-time type ids.
Here is a partly implemented C++14 version (compile-time sorting is required):
#include <cstddef>
#include <type_traits>
#include <utility>
namespace detail {
template<typename T>
struct type_id {
constexpr static int value{};
};
template<const int *const A, const int *const B>
struct same_address : std::false_type {};
template<const int *const A>
struct same_address<A, A> : std::true_type {};
}// namespace detail
// TODO: implement
template<const int *const... I>
struct sort_array {
using type = std::integer_sequence<const int *const, I...>;
};
template<typename>
struct find_duplicates;
template<const int *const A, const int *const B, const int *const... I>
struct find_duplicates<std::integer_sequence<const int *const, A, B, I...>> {
constexpr static bool value = std::conditional_t<detail::same_address<A, B>::value,
std::true_type,
find_duplicates<std::integer_sequence<const int *const, B, I...>>>::value;
};
template<>
struct find_duplicates<std::integer_sequence<const int *const>> {
constexpr static bool value = false;
};
template<const int *const I>
struct find_duplicates<std::integer_sequence<const int *const, I>> {
constexpr static bool value = false;
};
template<typename... T>
constexpr bool all_types_unique() {
return !find_duplicates<typename sort_array<&detail::type_id<T>::value...>::type>::value;
};
int main() {
static_assert(detail::same_address<&detail::type_id<int>::value,
&detail::type_id<int>::value>::value,
"");
static_assert(!detail::same_address<&detail::type_id<int>::value,
&detail::type_id<double>::value>::value,
"");
static_assert(all_types_unique<>(), "");
static_assert(all_types_unique<int>(), "");
static_assert(all_types_unique<int, double>(), "");
static_assert(all_types_unique<int, double, char>(), "");
static_assert(!all_types_unique<int, int>(), "");
static_assert(!all_types_unique<int, int, int>(), "");
return 0;
}
https://godbolt.org/z/E4G6YchE5
I want to write an adapter which can convert non static member functions to C-style function pointers. Here is what I got now(see the following code snippet), but the current solution is not general. I want to make int (T::*Func)(int) accept variable arguments.
Also it's necessary to make CObjectT::f and StoreVals::display have the same signature.
The final goal is Interfacing C++ member functions with C libraries.
class StoreVals
{
int val;
public:
int display(int k) { cout << k << endl; return 0; }
};
template<class T, int (T::*Func)(int)>
class CObjectT
{
public:
/*
* The signagure of 'f(...)' should change by the argument of template.
* They must be the same, but i don't know how to achieve this goal.
*/
static int f(int i)
{
T obj;
return (obj.*Func)(i);
}
};
void main()
{
CObjectT<StoreVals, &StoreVals::display>::f(7);
auto function_t = &CObjectT<StoreVals, &StoreVals::display>::f;
// Now it's a C-style function pointer
cout << typeid(function_t).name() << endl;
}
I don't think it is possible to dynamically change the name of a function based on a template parameter, but you can change the arguments/return type based on the template parameter. It does require some extra type information in the template declaration but it does allow what you want.
#include <iostream>
#include <utility>
template< typename T, T t >
class Delegate;
template< typename R, typename C, typename... Args, R ( C::*F ) ( Args... )>
class Delegate< R ( C::*)( Args... ), F > {
public:
template< typename... Ts >
static R invoke( Ts&&... args ) {
C t;
return ( t.*F )( std::forward< Ts >( args )... );
}
};
template< typename R, typename... Args, R ( *F ) ( Args... ) >
class Delegate< R ( * ) ( Args... ), F > {
public:
template< typename... Ts >
static R invoke( Ts&&... args ) {
return F( std::forward< Ts >( args )... );
}
};
void print( int v ) {
std::cout << "Static: " << v << std::endl;
}
class Class {
void print( int v ) {
std::cout << "Class: " << v << std::endl;
}
};
int main( int argc, char** argv ) {
Delegate< void ( * )( int ), &print >::invoke( 1 );
Delegate< void ( Class::* ) ( int ), &Class::print >::invoke( 1 );
return 0;
}
Output:
Static: 1
Class: 1
This does use C++11's variadic templates and Rvalue References for perfect forwarding. That is why you see the weird std::forward< Args >( args )... in the function calls.
This doesn't work with variadic parameter functions such as printf and the like. It might be possible but would require a lot more template black magic that I don't have time to write and test.
If you want to interface with C, you cannot use templates and you cannot use member functions (even static). The only way is a honest hand-written extern "C" function. Templates or member functions cannot have C linkage.
If you want to sacrifice portability for convenience you can do something like this:
#define TYPE_AND_VALUE(x) decltype(x),x
#define MemFuncTypeAdapter(x) MemFuncTypeAdapterStruct<TYPE_AND_VALUE(x)>
extern "C"
{
int (*cfunc)(struct A*, int);
}
template <typename MemFuncType> struct MemFuncTypes;
template <typename Class, typename Ret, typename... Args>
struct MemFuncTypes<Ret (Class::*)(Args...)>
{
using RetType = Ret;
using ClassType = Class;
};
template <typename MemFuncType, MemFuncType memFunc>
struct MemFuncTypeAdapterStruct
{
using RetType = typename MemFuncTypes<MemFuncType>::RetType;
using ClassType = typename MemFuncTypes<MemFuncType>::ClassType;
template <typename... Args>
static RetType func (ClassType* c, Args... args)
{
return (c->*memFunc)(args...);
}
};
struct A
{
A() : a(33) {};
int a;
int plus (int b) { return a + b; }
};
int main ()
{
MemFuncTypeAdapter(&A::plus) aplus;
A a;
aplus.func(&a, 22);
cfunc = &MemFuncTypeAdapter(&A::plus)::func; //<- C interface here
}
Notes.
The adapter has an additional Class* argument. See comments for an explanation of this.
Don't bother with perfect forwarding. You are passing C compatible types in there anyway. Which means scalars and pointers only.
The ugly macro is necessary to avoid repeating typename(x), x every time. Hopefully a future C++ standard will deal with it.
Parts of this can probably be found in the standard library, pointers are welcome.
Demo
BACKGROUND
I am trying to write a class template Hasher which will be implemented in two different ways depending on whether or not std::hash<T> has been implemented for T:
template<typename T>
struct Hasher
{
std::size_t hash( T t ) const;
// implement as A { std::hash<T> h; return h( t ); }
// or B { std::hash<std::string> h; return h( t.to_string() ); }
};
If std::hash<T> has been specialised, I want to use it. If not, I expect T to have a to_string() function to return a key for me to hash on.
For example, according to cppreference, if T is long long, a pointer, or std::string, I want version A. If it is not one of those standard ones listed and if the user has not specialised std::hash<T> for his own type, I expect T to have a std::string to_string() const for me to call. In this case, I want to generate version B.
PROBLEM
How do I use C++11/type_traits/no-SFINAE to generate the proper implementation?
ADDENDUM
Another way to think about it:
It's almost like I want version B to be the default behavior (ie, if no specialization exists, to use version B).
TESTED NAWAZ'S SOLUTION
I just tried out Nawaz's solution on gcc 4.8.1 as his came in first and is actually the easiest for me to read and understand (more important).
#include <functional>
#include <cassert>
template<typename T>
class Hasher
{
// overloading rules will select this one first... ...unless it's not valid
template<typename U>
static auto hash_impl(U const& u, int)
-> decltype(std::hash<U>().operator()( u ))
{
return std::hash<U>().operator()( u );
}
// as a fallback, we will pick this one
template<typename U>
static auto hash_impl(U const& u, ... )
-> std::size_t
{
return std::hash<std::string>().operator()(u.to_string());
}
public:
auto hash( T t ) const -> decltype( hash_impl(t,0) )
{
return hash_impl( t, 0 );
}
};
struct Foo
{
std::string m_id;
std::string to_string() const { return m_id; }
};
int
main( int argc, char** argv )
{
std::string s{ "Bar" };
Foo f{ s };
long long l{ 42ll };
Hasher<long long> hl;
Hasher<Foo> hf;
Hasher<std::string> hs;
assert( hl.hash( l )==l );
assert( hf.hash( f )==hs.hash( s ));
return 0;
}
TESTED DANIEL FREY'S SOLUTION
Daniel's implementation is also very interesting. By computing first whether or not we have a hash, I am able to use tag-dispatch to select the implementation I want. We have a nice pattern/separation-of-concerns which leads to very clean code.
However, in the implementation of has_hash<>, the arguments to decltype confused me at first. In fact, it shouldn't read as arguments. Rather, it is a list of expressions (comma separated expressions). We need to follow the rules as expressed here.
C++ ensures that each of the expressions is evaluated and its side
effects take place. However, the value of an entire comma-separated
expression is only the result of the rightmost expression.
Also, the use of void() was a mystery to me at first. When I changed it to double() to see what would happen, it was clear why it really should be void() (so we don't need to pass in that second template parameter).
#include <functional>
#include <cassert>
template< typename, typename = void >
struct has_hash
: std::false_type {};
template< typename T >
struct has_hash< T, decltype( std::hash< T >()( std::declval< T >() ), void() ) >
: std::true_type {};
template<typename T>
class Hasher
{
static std::size_t hash_impl(T const& t, std::true_type::type )
{
return std::hash<T>().operator()( t );
}
static std::size_t hash_impl(T const& t, std::false_type::type )
{
return std::hash<std::string>().operator()(t.to_string());
}
public:
std::size_t hash( T t ) const
{
return hash_impl( t, typename has_hash<T>::type() );
}
};
struct Foo
{
std::string m_id;
std::string to_string() const { return m_id; }
};
int
main( int argc, char** argv )
{
std::string s{ "Bar" };
Foo f{ s };
long long l{ 42ll };
Hasher<long long> hl;
Hasher<Foo> hf;
Hasher<std::string> hs;
assert( hl.hash( l )==l );
assert( hf.hash( f )==hs.hash( s ));
return 0;
}
You could use Expression SFINAE introduced by C++11.
Here is one example how it is implemented:
template<typename T>
struct Hasher
{
auto hash( T t ) const -> decltype(hash_impl(t,0))
{
return hash_impl(t, 0);
}
private:
template<typename U>
static auto hash_impl(U const & u, int) -> decltype(std::hash<U>().hash(u))
{
return std::hash<U>().hash(u);
}
template<typename U>
static auto hash_impl(U const & u, ... ) -> std::string
{
return u.to_string();
}
};
Note that hash_impl is an overloaded function template. So when you write this:
return hash_impl(t, 0);
Since the second argument 0 is int, the above first attempts to invoke hash_impl which uses std::hash — this attempt might fail if std::hash<U>().hash(u) is not a valid expression (Expression SFINAE). If that fails, then the second hash_impl is invoked.
You could just test if std::hash<T>()(...) can be called with type in question. If so, you'll get back a type from decltype() which can be used in a SFINAE expression to determine the size of a return type:
template <typename T>
struct has_hash
{
template <typename S>
static char (&test(S*, decltype(std::hash<S>()(std::declval<T&>()))* = 0))[1];
static char (&test(...))[2];
static constexpr bool value = 1 == sizeof(test(static_cast<T*>(0)));
};
Base on this you could then use the has_hash<T>::value to determine if there is a usable hash function already defined.
If you need to test if an expression is valid or not, I prefer the following implementation:
template< typename, typename = void >
struct has_hash
: std::false_type {};
template< typename T >
struct has_hash< T, decltype( std::hash< T >()( std::declval< T >() ), void() ) >
// ^^ expression here ------------------^^
: std::true_type {};
Live example
Yet another implementation
First, some boilerplate. type_sink and TypeSink let us evaluate types, and discard them.
template<typename... T> struct type_sink {typedef void type;};
template<typename... T> using TypeSink = typename type_sink<T>::type;
We then write a really simple has_hash that uses SFINAE. The default choice is "no hash", and the specialization is valid iff std::hash<T>()( t ) is a valid expression for a variable t of type T:
template<typename T, typename=void> struct has_hash:std::false_type {};
template<typename T> struct has_hash<
T, TypeSink< decltype( std::hash<T>()( std::declval<T&>() ) ) >
>: std::true_type {};
we then write our universal hasher:
template<typename T>
struct Hasher
{
private:
typedef has_hash< typename std::decay<T>::type > test_for_hash;
public:
std::size_t operator()( T t ) const {
return hash( std::forward<T>(t), test_for_hash() );
}
private:
std::size_t hash( T t, std::true_type has_hash ) const {
return std::hash<T>()( std::forward<T>(t) );
}
std::size_t hash( T t, std::false_type no_hash ) const {
// TODO: static_assert that t.to_string exists, and if not give a useful error message
return std::hash<std::string>()( std::forward<T>(t).to_string() )
}
};
where we use the has_hash trait to do tagged dispatching to either the "use hash directly" or "to_string then hash".
We can do more layers of this dispatching.
I took the liberty of making it somewhat move-aware, in that T can be T& or T const& or T and it behaves reasonably. (I don't know about T&& off the top of my head).
As noted in other comments, some work to generate better error messages can be done. We want the compiler's error message to complain about the lack of a hash<T> implementation rather than a to_string implementation probably. That would involve writing a has_to_string traits class and either doing another layer of tag dispatching, or doing a static_assert to generate a useful message telling the end user to implement either the hash<T> specialization or T::to_string.
Another option would be to make a universal hasher:
template<typename T>
struct Hasher
{
private:
typedef has_hash< T > test_for_hash;
public:
template<typename U>
std::size_t operator()( U&& u ) const {
return hash( std::forward<U>(u), test_for_hash() );
}
private:
template<typename U>
std::size_t hash( U&& u, std::true_type has_hash ) const {
return std::hash<T>()( std::forward<U>(u) ); // conversion occurs here
}
template<typename U>
std::size_t hash( U&& u, std::false_type no_hash ) const {
// TODO: static_assert that t.to_string exists, and if not give a useful error message
T t = std::forward<U>(u); // conversion occurs here -- note, implicit on purpose!
return std::hash<std::string>()( std::move(t).to_string() )
}
};
which defers transformation-to-T until the last moment.
Is there a way in C++ to determine function signature of a callable object?
Consider following:
template< typename F >
void fun(F f)
{
// ...
}
Lets assume that fun is called only with callable "things".
Inside of fun I want to know what is the signature of function f. That should work with function pointers, references, wrappers, lambdas, binds, function objects (providing they have only one operator ()) and so on. I'm limited with Visual Studio 2010 SP 1 but am interested in standard solutions even if not working on that compiler.
(A function signature is Return_Type ([Arg1_Type [, Arg2_Type [, ... ] ] ]); same as given to std::function/boost::function.)
A partial solution of knowing at least the return value of f is of some value to. (I have tried std::result_of but couldn't get it to work in any case I tried.)
On C++0x compliant compilers, you can at least get the result type of f() by using decltype(f()). Visual C++ 2010 should support decltype, though I haven't checked it myself yet. As for getting the argument types, I'm not sure if there's a way that would work with function pointers.
Edit
Boost.Function seems to have it figured out, at least on some compilers (it doesn't work on old versions of VC++ or Borland C++ for instance). It can wrap function pointers and extract arguments for them. The solution seems quite complex however, and it involves defining multiple templates with Boost.PP. If you feel like trying to re-implement everything you can certainly try that, but I think you can also just use a dummy Boost.Function wrapper to make things easier, e.g. boost::function<decltype(f)>::second_argument_type to get the second argument type.
You may look at Boost Function Types:
http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/boost_functiontypes/introduction.html
While trying to solve this I came up with following partial solution:
#include <cstdlib>
#include <functional>
#include <iostream>
#include <typeinfo>
#include <boost/bind.hpp>
#include <boost/function.hpp>
template< typename T >
struct identity
{
typedef T type;
};
// ----------
// Function signature metafunction implementation
// Also handler for function object case
// ----------
template< typename T >
struct function_signature_impl
: function_signature_impl< decltype( &T::operator() ) >
{
};
// ----------
// Function signature specializations
// ----------
template< typename R >
struct function_signature_impl< R () >
: identity< R () >
{
};
template< typename R, typename A1 >
struct function_signature_impl< R ( A1 ) >
: identity< R ( A1 ) >
{
};
template< typename R, typename A1, typename A2 >
struct function_signature_impl< R ( A1, A2 ) >
: identity< R ( A1, A2 ) >
{
};
// ----------
// Function pointer specializations
// ----------
template< typename R >
struct function_signature_impl< R ( * )() >
: function_signature_impl< R () >
{
};
template< typename R, typename A1 >
struct function_signature_impl< R ( * )( A1 ) >
: function_signature_impl< R ( A1 ) >
{
};
// ----------
// Member function pointer specializations
// ----------
template< typename C, typename R >
struct function_signature_impl< R ( C::* )() >
: function_signature_impl< R () >
{
};
template< typename C, typename R, typename A1 >
struct function_signature_impl< R ( C::* )( A1 ) >
: function_signature_impl< R ( A1 ) >
{
};
template< typename C, typename R >
struct function_signature_impl< R ( C::* )() const >
: function_signature_impl< R () >
{
};
template< typename C, typename R, typename A1 >
struct function_signature_impl< R ( C::* )( A1 ) const >
: function_signature_impl< R ( A1 ) >
{
};
// ----------
// Function signature metafunction
// ----------
template< typename T >
struct function_signature
: function_signature_impl< T >
{
};
// ----------
// Tests
// ----------
template< typename F >
void test( F f )
{
typedef function_signature< F >::type signature_type;
std::cout << typeid( F ).name() << std::endl;
std::cout << '\t' << typeid( signature_type ).name() << std::endl;
std::cout << std::endl;
}
int foo( int )
{
return 0;
}
struct bar
{
int operator ()( int )
{
return 0;
}
};
struct cbar
{
int operator ()( int ) const
{
return 0;
}
};
struct abar1
{
int operator ()( int ) const
{
return 0;
}
int operator ()( int )
{
return 0;
}
};
struct abar2
{
int operator ()( int )
{
return 0;
}
int operator ()( double )
{
return 0;
}
};
struct mem
{
int f( int ) const
{
return 0;
}
};
int main()
{
test(
[]( int ) -> int { return 0; }
);
test(
foo
);
test(
&foo
);
test(
bar()
);
test(
cbar()
);
test(
std::function< int ( int ) >( &foo )
);
test(
boost::function< void ( int ) >( &foo )
);
/*
test(
std::bind( &mem::f, mem(), std::placeholders::_1 )
);
*/
/*
test(
boost::bind( &mem::f, mem(), _1 )
);
*/
/*
test(
abar1()
);
*/
/*
test(
abar2()
);
*/
return EXIT_SUCCESS;
}
(No code for checking agains inproper arguments was added.)
The idea is that function_signature< decltype( f ) >::type should be the signature of a call of f( ... ) where that "..." is the signature. This means in particular that pointer to member function is an invalid argument here (although the code does not check against this) since such pointer cannot be "called" directly.
At the end are tests which fail (in VS 2010). All due to operator () being overloaded. And this makes that code mostly useless as it will not work with the result of bind. But maybe it can be further developed.
Answer to André Bergner's query:
function_signature_impl never derives from itself. It is a type template which only means a loosely coupled family of actual types. But the actual types (even thou they belong to the same family) are distinct types.
The &T::operator() is a pointer to a call operator (operator()) of type T – obviously. Basically just a member function pointer (where the member function happens to be a call operator). While decltype of it is the type of that pointer. This might seem insignificant (especially that type_info::name of both shows the same) but for templates it does matter since one is a pointer while the other is a type (apparently).
This “case” is needed to cover for functors (types which objects are “callable”). Note that this unspecialized function_signature_impl is used only if the template argument T doesn’t match anything else among the listed “cases”.
I hope I got it right after that long time. Although I’m not sure if I ever truly and fully understood it. The code was a bit result of experimenting.
This answer was just given to me by SlashLife on freenode ##c++:
template <typename T, typename Signature>
struct signature_impl;
template <typename T, typename ReturnType, typename... Args>
struct signature_impl<T, ReturnType(T::*)(Args...)>
{
using type = ReturnType(Args...);
};
template <typename T>
using signature_t = signature_impl<T, decltype(&T::operator())>;
The caveats are that it only works if there is a unique operator() and it doesn't work for lambdas.
You can use std::is_invocable_r
How can I iterate over a tuple starting from, say, index 1 to 2? The following doesn't work.
using boost::fusion::cons;
typedef cons<A, cons<B, cons<C, cons<D> > > > MyTuple;
MyTuple tuple_;
template <class T>
struct DoSomething{
DoSomething(T& t) : t_(&t){ }
template <class U>
void operator()(U u){
boost::fusion::at<mpl::int_<u> >(*t_);
}
T* t_;
};
boost::mpl::for_each< boost::mpl::range_c<int, 1, 3> >( DoSomething<MyTuple>(tuple_) );
I'm not sure about your intent, but will the following code serve your purpose?
I used fusion all over instead of mpl.
struct DoSomething {
template< class U >
void operator()( U u ) const {
std::cout << u << '\n'; // an example
}
};
using namespace boost::fusion; // Sorry, for brevity
iterator_range<
result_of::advance_c< result_of::begin< MyTuple >::type, 1 >::type
, result_of::advance_c< result_of::begin< MyTuple >::type, 3 >::type
> ir( advance_c< 1 >( begin( tuple_ ) )
, advance_c< 3 >( begin( tuple_ ) ) );
for_each( ir, DoSomething() );
Hope this helps
Judging from your comment,
what you mentioned can be implemented probably by making a predicate
class which determines whether the specified class has the member function,
and using fusion::filter_view.
DEF_HAS_MEM_FUNC macro in the following code is explained at:
Is it possible to write a template to check for a function's existence?
#include <boost/fusion/include/cons.hpp>
#include <boost/fusion/include/filter_view.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/mpl/placeholders.hpp>
using namespace boost;
#define DEF_HAS_MEM_FUNC( name, func_name, signature ) \
template< class T > \
struct name { \
template< class U, U > struct mfp; \
\
template< class U > \
static char f( mfp< signature, &U::func_name >* ); \
\
template< class > static char (&f(...))[2]; \
\
enum { value = (sizeof( f<T>(0) ) == 1) }; \
}
DEF_HAS_MEM_FUNC( has_f, f, void(U::*)()const );
struct DoSomething {
template< class U >
void operator()( U& u ) const {
u.f();
}
};
struct A {};
struct B {
void f() const {}
};
typedef fusion::cons< A, fusion::cons< B > > MyTuple;
int main()
{
MyTuple tuple_;
fusion::filter_view< MyTuple const, has_f< mpl::_ > > v( tuple_ );
fusion::for_each( v, DoSomething() );
}