C++ templates: conditionally enabled member function - c++

I'm creating a very small C++ project, and I'd like to create a simple vector class for my own needs. The std::vector template class will not do. When the vector class is comprised of chars (i.e. vector<char>), I'd like it to be able to be compared to a std::string. After a bit of messing around, I wrote code that both compiles and does what I want. See below:
#include <string>
#include <stdlib.h>
#include <string.h>
template <typename ElementType>
class WorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
template <typename ET = ElementType>
inline typename std::enable_if<std::is_same<ET, char>::value && std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
template <typename ElementType>
class NotWorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
inline typename std::enable_if<std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
int main(int argc, char ** argv) {
// All of the following declarations are legal.
WorkingSimpleVector<char> wsv;
NotWorkingSimpleVector<char> nwsv;
WorkingSimpleVector<int> wsv2;
std::string s("abc");
// But this one fails: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
NotWorkingSimpleVector<int> nwsv2;
(wsv == s); // LEGAL (wanted behaviour)
(nwsv == s); // LEGAL (wanted behaviour)
// (wsv2 == s); // ILLEGAL (wanted behaviour)
// (nwsv2 == s); // ??? (unwanted behaviour)
}
I believe I understand why the error is occurring: The compiler creates the class definition for NotWorkingSimpleVector<int>, and then the return type of my operator== function becomes:
std::enable_if<std::is_same<int, char>::value, bool>::type
which then becomes:
std::enable_if<false, bool>::type
which then yields an error: there is no type member of std::enable_if<false, bool>, which is indeed the entire point of the enable_if template.
I have two questions.
Why won't SFINAE simply disable the definition of operator== for NotWorkingSimpleVector<int>, like I want it to? Is there some compatibility reason for this? Are there other use-cases I'm missing; does a reasonable counter-argument for this behaviour exist?
Why does the first class (WorkingSimpleVector) work? It seems to me that the compiler 'reserves judgement': Since the 'ET' parameter is not yet defined, it gives up trying to tell if operator== can exist. Are we relying on the compilers 'lack of insight' to allow this kind of conditionally enabled function (even if this 'lack of insight' is acceptable by the C++ specification)?

SFINAE works in a template function. In the context of template type substitution, substitution failure in the immediate context of the substitution is not an error, and instead counts as substitution failure.
Note, however, that there must be a valid substitution or your program is ill formed, no diagnostic required. I presume this condition exists in order that further "more intrusive" or complete checks can be added to the language in the future that check the validity of a template function. So long as said checks are actually checking that the template could be instantiated with some type, it becomes a valid check, but it could break code that expects that a template with no valid substitutions is valid, if that makes sense. This could make your original solution an ill formed program if there is no template type you could pass to the operator== function that would let the program compile.
In the second case, there is no substitution context, so SFINAE does not apply. There is no substitution to fail.
Last I looked at the incoming Concepts proposal, you could add requires clauses to methods in a template object that depend on the template parameters of the object, and on failure the method would not be considered for overload resolution. This is in effect what you want.
There is no standards-compliant way to do this under the current standard. The first attempt is one that may people commonly do, and it does compile, but it is technically in violation of the standard (but no diagnostic of the failure is required).
The standards compliant ways I have figured out to do what you want:
Changing one of the parameters of the method to be a reference to a never-completed type if your condition fails. The body of the method is never instantiate if not called, and this technique prevents it from being called.
Using a CRTP base class helper that uses SFINAE to include/exclude the method depending on an arbitrary condition.
template <class D, class ET, class=void>
struct equal_string_helper {};
template <class D, class ET>
struct equal_string_helper<D,ET,typename std::enable_if<std::is_same<ET, char>::value>::type> {
D const* self() const { return static_cast<D const*>(this); }
bool operator==(const std::string & other) const {
if (self()->count_ == other.length())
{
return memcmp(self()->elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
where we do this:
template <typename ElementType>
class WorkingSimpleVector:equal_string_helper<WorkingSimpleVector,ElementType>
We can refactor the conditional machinery out of the CRTP implementation if we choose:
template<bool, template<class...>class X, class...>
struct conditional_apply_t {
struct type {};
};
template<template<class...>class X, class...Ts>
struct conditional_apply_t<true, X, Ts...> {
using type = X<Ts...>;
};
template<bool test, template<class...>class X, class...Ts>
using conditional_apply=typename conditional_apply_t<test, X, Ts...>::type;
Then we split out the CRTP implementation without the conditional code:
template <class D>
struct equal_string_helper_t {
D const* self() const { return static_cast<D const*>(this); }
bool operator==(const std::string & other) const {
if (self()->count_ == other.length())
{
return memcmp(self()->elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
then hook them up:
template<class D, class ET>
using equal_string_helper=conditional_apply<std::is_same<ET,char>::value, equal_string_helper_t, D>;
and we use it:
template <typename ElementType>
class WorkingSimpleVector: equal_string_helper<WorkingSimpleVector<ElementType>,ElementType>
which looks identical at point of use. But the machinery behind was refactored, so, bonus?

Templating operator== basically makes it uncallable. You'd have to explicitly do:
myvec.operator==<char>(str);
The simplest solution might just to add a non-member function:
bool operator==(const WorkingVector<char>& vec, const std::string& s);
bool operator==(const std::string& s, const WorkingVector<char>& vec);
To enable SFINAE and to keep it as a member function, you'd have to forward your type to something else:
bool operator==(const std::string& s) const {
return is_equal<ElementType>(s);
}
template <typename T> // sure, T == ET, but you need it in this context
// in order for SFINAE to apply
typename std::enable_if<std::is_same<T, char>::value, bool>::type
is_equal(const std::string& s) {
// stuff
}

Simple answer
This answer bares parallels to Yakk's answer but is not quite as useful (Yakk's one supports arbitrary if-expressions). It is, however, quite a bit simpler and easier to understand.
template <typename ThisClass, typename ElementType>
class WorkingSimpleVector_Base {
};
template <typename ThisClass>
class WorkingSimpleVector_Base<ThisClass, char> {
private:
ThisClass * me() { return static_cast<ThisClass*>(this); };
const ThisClass * me() const { return static_cast<const ThisClass*>(this); };
public:
bool operator==(const std::string & other) const {
if (me()->count_ == other.length())
{
return memcmp(me()->elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
template <typename ElementType>
class WorkingSimpleVector : public WorkingSimpleVector_Base<WorkingSimpleVector<ElementType>, ElementType> {
public:
const ElementType * elements_;
size_t count_;
};
This works by utilising template specialization for the 'if statements' we want. We base the class off of WorkingSimpleVector_Base, which then only contains functions if the ElementType value is char (second definition of WorkingSimpleVector_Base). Otherwise, it has no functions at all (first definition of WorkingSimpleVector_Base). The ThisClass parameter is what makes this a "CRTP" (Curiously Recurring Template Pattern). It allows the template to access the child class's fields through the use of the me() function. Remember that the template is no different from any other class so it won't have access to private members (unless the child class declares it as a friend).
Modified version of Yakk's answer explained
This first thing he/she declares is a helper template that does this whole conditional declaration for us:
template<bool, template<class...>class X, class...>
struct conditional_apply_t {
struct type {};
};
template<template<class...>class X, class...Ts>
struct conditional_apply_t<true, X, Ts...> {
using type = X<Ts...>;
};
template<bool test, template<class...>class X, class...Ts>
using conditional_apply=typename conditional_apply_t<test, X, Ts...>::type;
Variadic templates are scary, and I think they can be removed in this case. Let's simplify this to:
template<bool, class X>
struct conditional_apply_t {
struct type {};
};
template<class X>
struct conditional_apply_t<true, X> {
using type = X;
};
template<bool test, class X>
using conditional_apply=typename conditional_apply_t<test, X>::type;
conditional_apply_t's type type is an empty struct if the condition test is not true (see first definition of conditional_apply_t). If it is true, then the type type is the value of X. The definition of conditional_apply just removes the need for us to write ::type at the end of conditional_apply_t<...> every time we use this construct.
Next, we define a template that implements the behaviour we want
template <class D>
struct equal_string_helper_t {
D const* self() const { return static_cast<D const*>(this); }
bool operator==(const std::string & other) const {
if (self()->count_ == other.length())
{
return memcmp(self()->elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
In this case, the D parameter is what gives us the "CRTP" (Curiously Recurring Template Pattern). See the above "Simple Answer" for more details on why this is important.
Next, we declare a type that only has this operator== function if a condition is satisfied:
template<class D, class ET>
using equal_string_helper=conditional_apply<std::is_same<ET,char>::value, equal_string_helper_t<D>>;
So, the equal_string_helper<D,ET> type is:
An empty struct when ET != char
equal_string_helper_t<D> when ET == char
Finally, after all this, we can create the class we wanted with the following:
template <typename ElementType>
class WorkingSimpleVector : public equal_string_helper<WorkingSimpleVector<ElementType>, ElementType> {
public:
const ElementType * elements_;
size_t count_;
};
Which works as required.

Related

SFINAE User-Defined-Conversion Operator

I'm trying to do a templated user-defined-conversion that uses design by introspection.
In C++20 I can do the following:
template<typename T>
operator T() const
{
if constexpr( requires { PFMeta<T>::from_cursor(*this); } )
{
return PFMeta<T>::from_cursor(*this);
}
else
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
}
i.e. if PFMeta<T>::from_cursor(const struct PFCursor&) is defined then use it else do a memcpy. (longer example here in godbolt: https://godbolt.org/z/abed1vsK3)
I love this approach but unfortunately this library will need to work on C++17 too.
So I've been trying SFINAE as an alternative to the concepts but it's very tricky.
I finally managed to get something similar but with a templated method as rather than the user-defined-conversion operator itself:
template<typename T, typename = void>
struct has_from_cursor : std::false_type { };
template<typename T>
struct has_from_cursor<T, decltype( PFMeta<T>::from_cursor(std::declval<struct PFCursor>()), void() ) > : std::true_type { };
// ...
template<class T>
std::enable_if_t<has_from_cursor<T>::value, T> as() const
{
return PFMeta<T>::from_cursor(*this);
}
template<class T>
std::enable_if_t<!has_from_cursor<T>::value, T> as() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
I tried the following which compiles but does not work (I can't cast with it):
template<typename T>
operator std::enable_if_t<has_from_cursor<T>::value, T>() const
{
return PFMeta<T>::from_cursor(*this);
}
template<typename T>
operator std::enable_if_t<!has_from_cursor<T>::value, T>() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
Longer example here: https://godbolt.org/z/5r9Mbo18h
So two questions:
Can I do effectively what I can do with concepts with just SFINAE in C++17 for the user defined conversion operator?
Is there a simpler way to do the as approach than the type traits & enable_if? Ideally I'd like to do something like define the default templated method and then have a specialisation to be preferred if the condition is there (i.e. there is a meta class with a static member function defined).
Thanks!
Can I do effectively what I can do with concepts with just SFINAE in C++17 for the user defined conversion operator?
Consider that C++17 support if constepr. Given that you've developed a has_from_cursor custom type traits that inherit from std::true_type or from std::false_type, you can use it for if constexp.
I mean (caution: code not tested)
template<typename T>
operator T() const
{ // .............VVVVVVVVVVVVVVVVVVVVVVVVV
if constexpr( has_from_cursos<T>::value )
{
return PFMeta<T>::from_cursor(*this);
}
else
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
}
Is there a simpler way to do the as approach than the type traits & enable_if? Ideally I'd like to do something like define the default templated method and then have a specialisation to be preferred if the condition is there (i.e. there is a meta class with a static member function defined).
I suppose you can try tag-dispatching...
I mean something as calling 'as()', from operator T() with an additional int argument
template<typename T>
operator T() const
{ return as<T>(0); } // <-- call as() with a int
where there is a as() specific for from_cursos class enabled, that receive an unused int and is simply SFINAE enabled/disabled through decltype()
template <typename T> // ........accept an int; best match
decltype(PFMeta<T>::from_cursor(*this)) as (int) const
{ return PFMeta<T>::from_cursor(*this); }
and a generic as(), receiving a long
template <typename T>
T as (long) const // <-- accept a long; worst match
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
The trick is the unused argument: a int.
When the specialized as() is enabled, if preferred because accept a int so is a better match.
When the specialized as() is disabled, remain the generic as() as better-than-nothig match.

Curiously Recurring Pattern and Sfinae

I've been meaning to implement total ordering via SFINAE and the Curiously Recurring Template Pattern idiom for a while now. The general idea is as follows:
Define templates that check for relational operators (<, >, etc.)
Define base classes that define total ordering operators.
Define a base class from operator detection.
Inherit from base class.
For simplicity, I have ignored the == and != operators in this example.
Relational Operator Detection
I first define classes to statically check whether the class defines a specific feature. For example, here I detect the presence of the less-than operator, or operator<.
template <typename T>
class has_less
{
protected:
template <typename C> static char &test(decltype(std::declval<C>() < std::declval<C>()));
template <typename C> static long &test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(char)
};
};
template <typename T>
constexpr bool has_less_v = has_less<T>::value;
Total Ordering
I then define classes that implement total ordering from a given operator, for example, to define total ordering from the less-than operator, I would use the following:
template <typename T>
struct less_than_total
{
bool operator>(const T &t) { return t < static_cast<T&>(*this); }
bool operator>=(const T &t) { return !(static_cast<T&>(*this) < t); }
bool operator<=(const T &t) { return !(t < static_cast<T&>(*this)); }
};
Base Class
I then define a single base class that creates a typedef to implement the remaining operators by detecting the implemented operator.
template <bool B, typename T, typename F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <typename T>
using total_ordering = conditional_t< // has_less
has_less_v<T>,
less_than_total<T>,
conditional_t< // has_less_equal
has_less_equal_v<T>,
less_equal_total<T>,
conditional_t< // has_greater
has_greater_v<T>,
greater_total<T>,
conditional_t< // has_greater_equal
has_greater_equal_v<T>,
greater_equal_total<T>,
symmetric<T> // symmetry
> // has_greater_equal
> // has_greater
> // has_less_equal
>; // has_less
Inheritance
All of these steps, individually, work. However, when I actually inherit from the base class using the curiously recurring pattern, the resulting class implements only one of these operators and the detection algorithms fail.
Example
I've boiled down the issue to a minimal example consisting of the core parts: operator detection (has_less, has_greater), total ordering implementation (total), a simplified base class (total), and a simple struct using these relational operators (A).
#include <type_traits>
// DETECTION
template <typename T>
class has_less
{
protected:
template <typename C> static char &test(decltype(std::declval<C>() < std::declval<C>()));
template <typename C> static long &test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(char)
};
};
template <typename T>
class has_greater
{
protected:
template <typename C> static char &test(decltype(std::declval<C>() > std::declval<C>()));
template <typename C> static long &test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(char)
};
};
// TOTAL ORDERING
template <typename T>
struct less_than_total
{
bool operator>(const T &t) { return t < static_cast<T&>(*this); }
bool operator>=(const T &t) { return !(static_cast<T&>(*this) < t); }
bool operator<=(const T &t) { return !(t < static_cast<T&>(*this)); }
};
template <typename T>
struct symmetry
{};
template <bool B, typename T, typename F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <typename T>
struct total: conditional_t<
has_less<T>::value,
less_than_total<T>,
symmetry<T>
>
{};
// TEST
struct A: total<A>
{
bool operator<(const A &r)
{
return true;
}
};
int main(void)
{
static_assert(has_less<A>::value, "");
static_assert(has_greater<A>::value, "");
return 0;
}
Ideally, this example would compile, however, I get:
$ clang++ a.cpp -o a -std=c++14
a.cpp:79:5: error: static_assert failed ""
static_assert(has_less<A>::value, "");
^ ~~~~~~~~~~~~~~~~~~
a.cpp:80:5: error: static_assert failed ""
static_assert(has_greater<A>::value, "");
Unfortunately, the base class is not detecting the operators during inheritance, and SFINAE does not detect the less than or greater than operators in the resulting class.
Question and Follow-Up
I would like to know why this fails, since I have been doing member-function detection and member-type detection for a long time with the curiously recurring pattern without problem. And assuming there is no direct issue with my code, are there any work-arounds to implement total ordering in such a manner?
Edit
I'm able to achieve a subset of what I want using std::enable_if. In this case, the only simple answer is to implement everything in terms of operator< and then implement total ordering from that operator.
template <typename T>
struct total
{
template <typename U = T>
typename std::enable_if<has_less<U>::value, bool>::type
bool operator>(const T &l, const T &r) { return r < t; }
};
If would still like an answer for why my operator detection via SFINAE fails during inheritance, but succeeds for inherited methods.
The main problem with this is that A is an incomplete type when has_less<A> is instantiated (during the instantiation of total<A> as A's base class) -- at this point, the compiler doesn't yet know that A has an operator <.
So, has_less<A> is instantiated with its value == 0, and symmetry<A> is selected for total<A>'s base class -- so A never gets any of its additional operators.
After all this is decided, the compiler sees the definition of A::operator <, which it adds to A. After this, A is complete.
So we know why static_assert(has_greater<A>::value, ""); fails, but shouldn't we expect static_assert(has_less<A>::value, ""); to succeed? After all, now A has a less-than operator. The thing is, has_less<A> was already instantiated with the incomplete A, with value == 0 -- even though A has changed, there is no mechanism for updating previously instantiated compile-time values. So this assertion fails too, even though it looks like it should succeed.
To show that this is the case, make a copy of has_less, name it has_less2, and change the static assertion to static_assert(has_less2<A>::value, "");. Because has_less2<A> is instantiated after A gets its less-than operator, this assertion succeeds.
One way you can make the code succeed is to forward-declare A and declare a global operator <, for comparing two A objects, so that the compiler knows about this operator before A's base class is worked out. Something like this:
struct A;
bool operator < (const A &lh, const A& rh);
struct A : total<A> {
friend bool operator < (const A &lh, const A& rh) {
return true;
}
};
I understand that this is not really what you want, however -- it would be much nicer if the CRTP setup happened automatically, without any special accommodation required in the derived class. But this might still give you some insight which can help lead you to a proper solution. I will also think about this some more, and if I come up with anything, I'll update this answer.
One more thing: Comparison member functions should be const qualified. Like
bool operator>(const T &t) const { ...
This is really important and will prevent a lot of non-obvious problems compiling code which uses these classes later on.

Type-traits experimentation, SFINAE seems not to be working, whines about the absence of something in the form of an error

I'm trying to use C++11, rather than using C++ as C++98 (I come from C) and I've hit type-traits, now rather than jumping in to the standard I thought I'd try and solve the problem.
Usually I'd use inheritance to add methods based on the type, and rely on the user, but I want to use traits, now I don't expect the end user to use my "custom ones", this is because it's an experiment.
I started by creating a True and a False type, as so:
struct True {
static const bool value = true;
};
struct False {
static const bool value = false;
};
Then my enable_if definition, which I understand to use the fact that a struct or class is both a struct (in the C sense, has a size and such) and a namespace, as so:
template<bool B,class T>
struct EnableIf {};
template<class T>
struct EnableIf<true,T> {
typedef T type;
};
I now expect that only EnableIf with true to have a "namespace type member" (if I may) called "type" which is whatever the template T is. This seems to work.
I understand that the false/default case should "silently fail" when I try and access EnableIf<false,T>::type because of the absence of type
I'm pretty sure everything so far is right, but I'm just being verbose.
My test case
I've chosen a list as my testing ground (again not using the standard set because I am investigating) Usually I use a class hierarchy to do this, I'd have a list that could do nothing more than act as an array, the only extra member would be int find(T*); because a T* is a T's identity.
Then I'd extend that to have a int find(T&); int find(T&,int) and int count(T&) and this'd use == to compare Ts. This is what I mean by leaving it up to the user, they could chose the list they wanted based on what /they/ knew about the type.
I want to use EnableIf (later std::enable_if when I feel more confident) to do this instead, that way when the template is stamped out functionality is only enabled if the type is able to be used that way.
List definition
template<class T>
class List {
public:
typedef typename T::hasEquality hasEquality;
virtual ~List() {}
virtual T& operator[](int index) =0;
virtual const T& operator[](int index) const =0;
virtual void append(T*) =0;
virtual int length() const =0;
virtual
typename EnableIf<hasEquality::value, bool>::type
operator==(const List<T>& rhs) const {
if(length() == rhs.length()) {
for(int k=0;k!=length();k++) {
if(!((*this)[k] == rhs[k])) {
return false;
}
}
return true;
} else {
return false;
}
}
virtual
typename EnableIf<T::hasEquality::value, int>::type
count(const T& what) const =0;
};
It's a list not a set so order matters. You can see that this should make hasEquality transitive in the sense that:
if T has the concept of equality than a list of T has the concept of equality also
I then go on to implement a singly-linked-list.
Testing types
class A {
public:
A(int value) { val = value; }
typedef True hasEquality;
bool operator==(const A& rhs) const {
if(val == rhs.val) {
return true;
}
return false;
}
private:
int val;
};
class B {
public:
typedef False hasEquality;
};
Results
int main(int,char**) {
LinkedList<A> listA;
listA.append(new A(6));
A a(6);
std::cout<<"there are "<<listA.count(a)<<" of them\n";
return 0;
}
As you'd expect this works. My first test initially included B but that causes problems.
int main(int,char**) {
LinkedList<A> listA;
listA.append(new A(6));
A a(6);
std::cout<<"there are "<<listA.count(a)<<" of them\n";
LinkedList<B> listB;
return 0;
}
This does not, it fails with:
src/main.cpp: In instantiation of ‘class List<B>’:
src/main.cpp:77:7: required from ‘class LinkedList<B>’
src/main.cpp:176:16: required from here
src/main.cpp:59:2: error: no type named ‘type’ in ‘struct EnableIf<false, bool>’
operator==(const List<T>& rhs) const {
^
src/main.cpp:73:3: error: no type named ‘type’ in ‘struct EnableIf<false, int>’
count(const T& what) const =0;
^
src/main.cpp: In instantiation of ‘class LinkedList<B>’:
src/main.cpp:176:16: required from here
src/main.cpp:134:3: error: no type named ‘type’ in ‘struct EnableIf<false, int>’
count(const T& what) const {
^
make: *** [build/main.o] Error 1
For some reason it puts the error marker after the typename line, it is unhappy everywhere I use an EnableIf with false
I am really not sure why this is, it is right, there is no type, but this is by design!
Research
http://en.cppreference.com/w/cpp/types/enable_if
To quote that:
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
Mine differs only by name and the default T being void, adding this to mine (as I expected) does not fix the problem.
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/SFINAE
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/enable-if
Confirm my thoughts.
Bonus questions
constexpr and static
Initially I tried struct False { constexpr bool operator==(bool what) { return !what; } }; and the same for True;
But this did not work, and I cannot use the word "static" to qualify operator==, but I could have used a method called constexpr static bool is(bool what); for the same effect, why doesn't constexpr imply static?
In my mind constexprs never really exist, and the design is sort of like the opposite of virtual, there's nothing that says you cannot use an instance to call a static method, I've just checked C++03 standard, section 9.4 confirms this, has this changed?
SFINAE
Would it be possible to use SFINAE to assume False when hasMember has not been defined? I understand this wont work for the fundamental types and such, this is an experiment. I will not use these techniques in production stuff until I am confident.
The problem is here:
virtual
typename EnableIf<T::hasEquality::value, int>::type
count(const T& what) const =0;
You hit another example where generic programming (templates) and object oriented programming styles conflict.
SFINAE is a metaprogramming technique that works with templates. Despite the appearence (the use of T), the function declared above is not a template. It's a normal function inside a template class. The template type parameter T is a parameter of List and not of count.
For instance, the following is an example of SFINAE:
template<class T>
class List {
public:
template<class T>
class List {
public:
// ...
template <typename U>
typename EnableIf<std::is_same<U, T>::value && U::hasEquality::value, int>::type
count(const U& what) const { std::cout << "1\n"; }
template <typename U>
typename EnableIf<std::is_same<U, T>::value && !U::hasEquality::value, int>::type
count(const U& what) const { std::cout << "2\n"; }
};
};
int main() {
A a(1);
B b;
List<A> la;
la.count(a); // outputs 1
List<B> lb;
lb.count(b); // ouputs 2
}
Notice that the two counts are now a templates (parametrized on U). Both are active only if T is the same type as U. This is a workaround to accept T only (it's not perfect, for instance, it discards implicit conversions). The first requires, in addition, that U::hasEquality::value == true and the second requires the opposite.
The key point here is that SFINAE works on templates.
But as you can see I changed your design and made count non virtual. Unfortunately, you cannot make the count functions above virtual because template functions cannot be virtual.
The basic issue is as follows. Template functions are instanciated only when they are called. So when the compiler parses List (my version) it doesn't know yet all the instantiations of count that are going to exist.
For each virtual function there should be an entry in the virtual table and when the compiler parses List it must know how many entries there are in the virtual table.
Hence, on one hand, when parsing List the compiler doesn't know the number of template instancitaions and, on the other hand, it must know the number of virtual functions. The conclusion is that template functions cannot be virtual.
SFIANE only applies to template argument deduction and overload resolution of functions. For classes you can instead use template specialization. In your case you could do template specialization something like this (no EnableIf required):
template <typename T, typename = typename T::hasEquality>
class List;
template <typename T>
class List<T, False> {
// no operator==
};
template <typename T>
class List<T, True> {
public:
// ...
bool operator==(const List<T,True>& rhs) const {
// ...
}
// ...
};
As to your constexpr question, you can have constexpr constructors that create compile time object you can then call constexpr member functions on that will run at compile time, so it doesn't make sense for constexpr to imply static.
It's too late for me to be answering questions it seems. You can use SFINAE to conditionally enable a member function, it just has to be a template function. So you can change your operator== to
template <typename = typename EnableIf<T::hasEquality::value, void>::type>
bool operator==(const List<T>& rhs) const {
// ...
}
and it should work.

How do I make a class that only compiles when its type has a certain member function?

I have a class named has_f and I want it to only accept template parameters that have a f member function. How would I do that? This is what I tried:
template <typename T, typename = void>
struct has_f : std::false_type {};
template <typename T>
struct has_f<
T,
typename = typename std::enable_if<
typename T::f
>::type
> : std::true_type {};
But I get some cryptic errors. Here is the class I want to use:
struct A
{
void f();
};
How do I do this correctly? Thanks.
From the title of your question I presume that you don't really need a type deriving from true_type or false_type - only to prevent compilation if method f is not present. If that is the case, and if you also require a specific signature (at least in terms of arguments) for that method, in C++11 you can do something like this:
template <typename T>
struct compile_if_has_f
{
static const size_t dummy = sizeof(
std::add_pointer< decltype(((T*)nullptr)->f()) >::type );
};
This is for the case when f() should not accept any arguments. std::add_pointer is only needed if f returns void, because sizeof(void) is illegal.
I +1ed rapptz yesterday for
"possible duplicate of
Check if a class has a member function of a given signature"
and haven't changed my mind.
I suppose it is arguable that this question unpacks to
"A) How to check if a class has a member function of a given signature and
B) How to insist that a class template argumement is a class
as per A)". To B) in this case I would answer with static_assert, since
the questioner apparently isn't interested in enable_if alternatives.
Here is a solution that adapts my answer to
"traits for testing whether func(args) is well-formed and has required return type"
This solution assumes that has_f<T>::value should be true if and only
if exactly the public member void T::f() exists, even if T overloads f or inherits f.
#include <type_traits>
template<typename T>
struct has_f
{
template<typename A>
static constexpr bool test(
decltype(std::declval<A>().f()) *prt) {
return std::is_same<void *,decltype(prt)>::value;
}
template <typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<T>(static_cast<void *>(nullptr));
};
// Testing...
struct i_have_f
{
void f();
};
struct i_dont_have_f
{
void f(int);
};
struct i_also_dont_have_f
{
int f();
};
struct i_dont_quite_have_f
{
int f() const;
};
struct i_certainly_dont_have_f
{};
struct i_have_overloaded_f
{
void f();
void f(int);
};
struct i_have_inherited_f : i_have_f
{};
#include <iostream>
template<typename T>
struct must_have_f{
static_assert(has_f<T>::value,"T doesn't have f");
};
int main()
{
must_have_f<i_have_f> t0; (void)t0;
must_have_f<i_have_overloaded_f> t1; (void)t1;
must_have_f<i_have_inherited_f> t2; (void)t2;
must_have_f<i_dont_have_f> t3; (void)t3; // static_assert fails
must_have_f<i_also_dont_have_f> t4; (void)t4; // static_assert fails
must_have_f<i_dont_quite_have_f> t5; (void)t5; // static_assert fails
must_have_f<i_certainly_dont_have_f> t6; (void)t6; // static_assert fails
must_have_f<int> t7; (void)t7; // static_assert fails
return 0;
}
(Built with clang 3.2, gcc 4.7.2/4.8.1)
This toes a fine line between answering your question and providing a solution to your problem but not directly answering your question, but I think you may find this helpful.
For background, check out this question. The author mentions that he didn't like Boost's solution, and I didn't particularly like the one proposed there either. I was writing a quick & dirty serialization library (think python's marshal) where you would call serialize(object, ostream) on an object to serialize it. I realized I wanted this function call to one of four things:
If object is plain old data, just write out the size and raw data
If object is a class that I've created with its own member function (object::serialize), then call that member function
If there's a template specialization for that type, use it.
If none of the above is true, throw a compilation error; the serialize function is being used improperly.
When I code, I try to avoid stuff that is 'tricky' or hard to understand at a glance. I think this solution solves the same problem without using code that must be pondered for hours to understand:
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
// Template specialization for a POD object
template<typename T>
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
os.write((const char*) &out, sizeof(T));
return os.good();
}
// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T>
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
return out.serial(os);
}
// Additional specializations here for common container objects
template<typename T>
bool serial(const std::vector<T> &out, std::ostream &os)
{
const size_t vec_size = out.size();
if(!serial(vec_size, os))
return false;
for(size_t i =0; i < out.size(); ++i)
{
if(!serial(out[i], os))
return false;
}
return true;
}
class SomeClass
{
int something;
std::vector<double> some_numbers;
...
bool serial(std::ostream &os)
{
return serial(something, os) && serial(some_numbers, os);
}
};
If you can boil down your needs to a simple set of rules, and can live with a slightly less general solution, I think this method works well.

How to tell if class contains a certain member function in compile time [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?
say there are 2 classes:
struct A{ int GetInt(){ return 10; } };
struct B{ int m; };
I want to use object of type A or B in following function
tempate< typename T >
int GetInt( const T & t )
{
//if it's A, I'll call: return t.GetInt();
//if its' B, I'll call: return t.m;
}
Now, because there are whole bunch of classes, some contain GetInt(), some don't, I don't want to write specialization for each type, I only want to distinguish them by 'containing GetInt() or not in compile time', how should I do this ?
Substitution Failure Is Not An Error, or more compactly, SFINAE
But in your particular case, you don't need SFINAE, virtual members, or anything fancy like that.
You just need an ordinary overloaded function.
int GetInt(A& t) { return t.GetInt(); }
int GetInt(const B& t) { return t.m; }
If there's code that needs to be shared between the different versions, refactor it so that there's a template that calls an overloaded inline function, all type-specific behavior is in the inline function, and all shared behavior is in the template.
For your "I have many many classes" need, SFINAE would look more or less like this:
template<typename T>
int GetInt(const T& t, int (T::*extra)() const = &T::GetInt)
{
return t.GetInt();
}
template<typename T>
auto GetInt(const T& t) -> decltype(t.m)
{
return t.m;
}
EDIT: The reality of SFINAE is much uglier, at least until C++0x comes around. In fact it starts looking just as bad as GMan's answer.
struct A{ int GetInt() const { return 10; } };
struct B{ int m; };
template<typename T, int (T::*extra)() const>
struct has_mfunc
{
typedef int type;
};
template<typename T>
typename has_mfunc<T, &T::GetInt>::type GetInt(const T& t)
{
return t.GetInt();
}
template<typename T, typename U, U (T::*extra)>
struct has_field
{
typedef U type;
};
template<typename T>
typename has_field<T, int, &T::m>::type GetInt(const T& t)
{
return t.m;
}
int main(void)
{
A a;
B b;
b.m = 5;
return GetInt(a) + GetInt(b);
}
Stealing from here, and assuming you fix your code so GetInt is const, we get:
HAS_MEM_FUNC(GetInt, has_GetInt);
template <bool B>
struct bool_type
{
static const bool value = B;
};
typedef bool_type<true> true_type;
typedef bool_type<false> false_type;
namespace detail
{
template <typename T>
int get_int(const T& pX, true_type)
{
return pX.GetInt();
}
template <typename T>
int get_int(const T& pX, false_type)
{
return pX.m;
}
}
template <typename T>
int get_int(const T& pX)
{
return detail::get_int(pX,
has_GetInt<T, int (T::*)() const>::value);
}
This is pretty awful design though. You should fix the problem rather than apply a patch.
Technically it just involves a few template arcana, which you can find by googling e.g. has_member or the like. Off the cuff, in the detection code, if I were to write such, I'd just sort of fake-derive from the class in question, and check size of derived class' member.
However, don't do that.
What else to do depends. But it seems like your classes conform to two different "schemas", so to speak, without those schemas being available via the type system (like, it seems the classes don't derive from two base classes A and B). Then one option is to introduce a traits template that tells you wrappers whether the template param T is schema A or B. Specialize the traits for each relevant class that differs from the default. Choose the default so as to minimize work.
Cheers & hth.,
This is exactly what inheritance is for. You can easily use use dynamic_cast for is type of questions at runtime. For example you can define an abstract base class called HasGetInt and derive the classes that need that function from it and not reinvent the wheel.