does sfinae instantiates a function body? - c++

I want to detect existence of a specific member function for a class, using the usual SFINAE trick.
template<typename T>
struct has_alloc
{
template<typename U,U x>
struct dummy;
template<typename U>
static char test(dummy<void* (U::*)(std::size_t),&U::allocate>*);
template<typename U>
static char (&test(...))[2];
static bool const value = sizeof(test<T>(0)) ==1;
};
It should be noted that this detects a different kind of allocator which has void* allocate(std::size_t) as member function which are non standard (probably some raw memory allocator).
Next, I have an incomplete type and an std::allocator for that incomplete type.
struct test;
typedef std::allocator<test> test_alloc;
And I am checking whether the test_alloc is the one I am looking for.
struct kind_of_alloc
{
const static bool value = has_alloc<test_alloc>::value;
};
Surely struct test will be complete when I will "use" test_alloc such as
#include "test_def.hpp"//contains the code posted above
struct test{};
void use()
{
test_alloc a;
}
in another compilation unit. However when the has_alloc test happens,the compiler tries to instantiate the allocate function for std::allocator and finds that sizeof an incomplete type is used inside function body, and causes a hard error.
It seems that the error doesn't occur if the implementation of allocate separated and included separately at the point of use such as
template<typename T>
T* alloc<T>::allocate(std::size_t n)
{
return (T*)operator new(sizeof(T)*n);
}
void use()
{
test_alloc a;
a.allocate(2);
}
And test_def.hpp contains
template<typename T>
struct alloc
{
T* allocate(std::size_t n);
};
However while I can do this for alloc<T> , it is not possible for std::allocator as separating out the implementation is not possible.
What I am looking for is it possible to test whether a function with void* allocate(size_t) exists in test_alloc. If not, it will test negative, and if yes ,i.e. if the function signature matches, even if it can not be instantiated there, test positive.

No, SFINAE is only in effect during overload resolution. Once a resolution has been made and the compiler begins instantiating the function SFINAE is over.
Edit: and taking the address of a function instantiates it.

Related

C++ how to check the signature of a template parameter class at compile time

In the code below, I am trying to check the signature of the class that is passed as the second template argument to WTrajectory. In the current implementation, the constructor of WTrajectory compares the types of the template argument T and the template argument of the type that is passed to it as the second argument.
The current implementation can perform the check. However, I would prefer to perform it at compile time, if it is possible. Moreover, I would also like to check if the template argument TWPoint has a member function returnTimeTypeID, also at compile time (a solution that performs this check at run time can be found here: link).
template<typename T>
struct WPoint
{
const std::type_info& returnTimeTypeID(void) const
{return typeid(T);}
};
template<typename T, typename TWPoint>
struct WTrajectory
{
WTrajectory(const TWPoint& wp)
{
compare_types(wp);
}
void compare_types(const TWPoint& wp)
{
if (typeid(T) != wp.returnTimeTypeID())
throw std::runtime_error("Error");
}
};
Since returnTimeTypeID is non-virtual the compiler will know the dynamic type of TWPoint at compile time. So instead of doing a runtime check just change your template:
template<typename T>
struct WTrajectory
{
typedef T TWPoint;
...
The best way to check whether a template type has a perticular method at compile time is to just call the method. You'll get a compilation error if it doesn't provide the needed functionality.
If WPoint contains more than just the type info, then the following code will work
template<typename T>
struct WPoint
{
// ... stuff not related to type checking
};
template<typename T>
struct WTrajectory
{
WTrajectory(const WPoint<T>& wp)
{
}
};
You could remove WPoint if it does not contain anything else besides the type info.

How can I get the class of a member function pointer?

Consider the code:
class Character
{
void kill();
void send_to_wall();
}
template <typename T>
void GeorgeFunc(T fp)
{
??? obj;
(obj.*fp)();
}
int main()
{
GeorgeFunc(&Character::kill);
}
So my question here is: how can I get ???? It seems that the compiler definitely knows what this type is (Character) during template instantiation, but I'm not sure how to get at it. My current workaround is to change to: void GeorgeFunc(void (T::*fp)()), but it would be cleaner to simply get the type from the member function pointer. decltype(fp) would return void(Character::*)(), and decltype(fp()) would return void. Any way to get Character?
Yes, just use a trait to determine this.
template <typename> struct member_function_traits;
template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...)>
{
typedef Return return_type;
typedef Object instance_type;
typedef Object & instance_reference;
// Can mess with Args... if you need to, for example:
static constexpr size_t argument_count = sizeof...(Args);
};
// If you intend to support const member functions you need another specialization.
template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...) const>
{
typedef Return return_type;
typedef Object instance_type;
typedef Object const & instance_reference;
// Can mess with Args... if you need to, for example:
static constexpr size_t argument_count = sizeof...(Args);
};
Now your declaration is:
typename member_function_traits<T>::instance_type obj;
However, I would argue that since you require a member function pointer (other types would fail to instantiate due to the line (obj.*fp)()1) that your function should take a member function pointer directly instead of a completely generic type.
So this definition would not only work, but I would consider it preferred -- the error messages when someone uses something other than a pointer-to-member-function will be much clearer because the argument type will be incompatible:
template <typename Return, typename Object>
void GeorgeFunc(Return (Object::*fp)())
{
Object obj;
(obj.*fp)();
}
Note that this does allow passing a pointer-to-member-function that returns any type. Since we don't really use the return value, we don't care what it is. There is no reason to enforce that it is void as in your "workaround."
The only downside to using this approach is that you need two overloads if you intend to also accept pointers to member functions that are declared const. The completely generic implementation does not have this limitation. (I've long wished that pointers to const member functions were implicitly convertible to pointers to non-const member functions, but this is currently not allowed by C++.)
1 This isn't 100% true. If you use a completely generic type as you are right now then the caller could theoretically pass a member data pointer instead of a member function pointer. obj.*fp would evaluate as a reference to the data member, and then you would be invoking operator()() on it. As long as the data member's type implemented this operator then the template function GeorgeFunc could be instantiated.

Invoke a may not existed member function by template

How can I call a may-existing member function by template technology, I am not want to use virtual method, because the class is arbitrary.
For example:
class A {
void setValue(int value);
};
How to define a template to call class A's setValue if it existing, else do nothing.
The template is something like:
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
It's about invoking, not checking.
You can take advantage of SFINAE to make a class template that checks for the existence of a member function in a given class, and use the result as a boolean flag to specialize your template for the case when there is no function, and the case when the member function exists:
template<typename T , bool member_exists = has_set_value<T>::result>
struct call_if_exist;
template <typename T>
struct call_if_exist<T,true> {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist<T,false> {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
Edit: The has_set_value trait
template<typename T>
class has_set_value
{
typedef struct{ char c[1]; } yes;
typedef struct{ char c[2]; } no;
template<typename U> static yes test(&U::set_value);
template<typename U> static no test(...);
public:
static const bool result = sizeof( test<T>(NULL) ) == sizeof( yes );
};
This class is the typical example of the usage of SFINAE to check for the existence of a member (type or function) of a certain class.
First we define two typedefs, yes and no, which are used to differentiate overload resolutions through the sizeof operator.
The first overload of test() has a pointer to the member function as parameter, and the last is an overload which goal is to be called by everything thats not a pointer to the member. This is done through a variadic-function (Note the ellipsis), which can be used with any kind of parameter.
The point of the implementation is even if the second overload can hold any parameter, the first is an explicit case for pointers to our member function. So if the parameter could be a pointer to the function, the call is resolved to the first function, else its resolved to the second.
As I said before, we use the typedefs to differentiate the overload resolution through the sizeof operator: Note that the first overload returns yes and the later returns no. So if the size of the result type of the call to test() using a pointer (NULL) is equal to the size of yes, means that the overload is resolved to the first, and the class passed as parameter (T) has a member function called set_value.
Alexandrescu's Modern C++ Dessign includes an example of this kind of trait in chapter two to check if one type is implicitly convertible to other.

Raise an exception for non-pointer template class?

I've got this queue class, actually, several that suffer from the same issue - performance will be poor if compiled with a type that has a lengthy copy ctor - the queue is locked during push/pop and the longer it is locked, the greater the chance of contention. It would be useful if the class would not compile if some developer tried to compile it with a 10MB buffer class, (instead of a pointer to it).
It seems that there is no easy way to restrict template parameters to base classes or any other type.
Is there some bodge I can use so that my class will not compile if the parameter is not a pointer to a class instance?
You can do this in several ways. As another answer points out you can do it with a static_assert (preferably from C++11/Boost although you can roll your own), although I'd recommend checking if it is actually a pointer and not just relying on the size. You can either roll your own or use an existing trait (available in C++11 too) depending on what system you're using:
template <typename T>
struct is_pointer {
enum { value = 0 };
};
template <typename T>
struct is_pointer<T*> {
enum { value = 1 };
};
template <typename T>
struct container {
static_assert(is_pointer<T>::value, "T must be a pointer");
void push(const T&);
T pop();
};
struct foo {};
int main() {
container<foo*> good;
container<foo> fail;
}
But that raises a bigger point. If your requirement is that you only ever point to things, why not interpret the template parameter like that to begin with? E.g. make your container:
template <typename T>
struct container {
void push(const T*);
T *pop();
};
instead of allowing people to specify non-pointer types in the first place?
Finally if you don't want to go down the static_assert road you can just specialise the container for pointer types only and not implement it for non-pointers, e.g.:
template <typename T>
struct container;
template <typename T>
struct container<T*> {
void push(const T*);
T *pop();
};
struct foo {};
int main() {
container<foo*> good;
container<foo> fail;
}
This still requires explicitly making the type a pointer, still causes compile time failure for non-pointer types, but doesn't need a static_assert or way of determining if a type is a pointer.
"Is there some bodge I can use so that my class will not compile if the parameter is not a pointer to a class instance?"
Not a bodge, but:
template<class T>
class MyContainer
{
public:
void AllMemberFunctions( T* in ){}
void OnlyAcceptTStars( T* in ){}
};
The user defines the type being held, and your functions only accept or handle pointers to that type.
(Or do what STL does, assume some intelligence on the part of the user and forget about the issue.)
Use a variant of static assert (just google for many possible implementations). Something like BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(void*)) should do the trick.
Yes, you can do it using static_assert. For example,
template<int N>
class Queue
{
static_assert(N < size, "N < size violated");
...
};

Semi-generic function

I have a bunch of overloaded functions that operate on certain data types such as int, double and strings. Most of these functions perform the same action, where only a specific set of data types are allowed. That means I cannot create a simple generic template function as I lose type safety (and potentially incurring a run-time problem for validation within the function).
Is it possible to create a "semi-generic compile time type safe function"? If so, how? If not, is this something that will come up in C++0x?
An (non-valid) idea;
template <typename T, restrict: int, std::string >
void foo(T bar);
...
foo((int)0); // OK
foo((std::string)"foobar"); // OK
foo((double)0.0); // Compile Error
Note: I realize I could create a class that has overloaded constructors and assignment operators and pass a variable of that class instead to the function.
Use sfinae
template<typename> struct restrict { };
template<> struct restrict<string> { typedef void type; };
template<> struct restrict<int> { typedef void type; };
template <typename T>
typename restrict<T>::type foo(T bar);
That foo will only be able to accept string or int for T. No hard compile time error occurs if you call foo(0.f), but rather if there is another function that accepts the argument, that one is taken instead.
You may create a "private" templatized function that is never exposed to the outside, and call it from your "safe" overloads.
By the way, usually there's the problem with exposing directly the templatized version: if the passed type isn't ok for it, a compilation error will be issued (unless you know your algorithm may expose subtle bugs with some data types).
You could probably work with templates specializations for the "restricted" types you want to allow. For all other types, you don't provide a template specialization so the generic "basic" template would be used. There you could use something like BOOST_STATIC_ASSERT to throw a compile error.
Here some pseudo-code to clarify my idea:
template <typename T>
void foo(T bar) {BOOST_STATIC_ASSERT(FALSE);}
template<> // specialized for double
void foo(double bar) {do_something_useful(bar);};
Perhaps a bit ugly solution, but functors could be an option:
class foo {
void operator()(double); // disable double type
public:
template<typename T>
void operator ()(T bar) {
// do something
}
};
void test() {
foo()(3); // compiles
foo()(2.3); // error
}
Edit: I inversed my solution
class foo {
template<typename T>
void operator ()(T bar, void* dummy) {
// do something
}
public:
// `int` is allowed
void operator ()(int i) {
operator ()(i, 0);
}
};
foo()(2.3); // unfortunately, compiles
foo()(3); // compiles
foo()("hi"); // error
To list an arbitrary selection of types I suppose you could use a typelist. E.g see the last part of my earlier answer.
The usage might be something like:
//TODO: enhance typelist declarations to hide the recursiveness
typedef t_list<std::string, t_list<int> > good_for_foo;
template <class T>
typename boost::enable_if<in_type_list<T, good_for_foo> >::type foo(T t);