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.
Related
Q: Are there are any compile time mechanisms in C++ I can use to automatically verify that the set of template class methods matches from class specialization to specialization?
Example: Let us suppose I want a class interface that has very different behaviors depending on a template value specialization:
// forward declaration of template class name
template <typename T, bool isZero> class MyClass;
// partial class specialization for isZero = false case
template <typename T> class MyClass <T, false>
{
T _val;
public:
MyClass(T value) { _val = value; }
T GetValue(void) const { return _val; }
};
// partial class specialization for isZero = true case
template <typename T> class MyClass <T, true>
{
public:
MyClass(T value) {}
T GetValue(void) const {return T(0);}
};
The idea here is that when compiling on Tuesdays, MyClass.GetValue() returns 0, whereas any other day of the week, we get the expected value ...or some such thing. The details and motivations are unimportant. ;-)
Now, while this seems like one way to achieve partial function specialization based on partial class specialization, it also seems like it can also be utter chaos because the two class specializations can (AFAIK) have completely inconsistent interfaces. If I am actually going to use this mechanism in a production setting, I would like some ideally compile time notification if I mistakenly add some methods to some specializations and not others or forget a const somewhere, etc. How do I get that?
For bonus points, let us suppose I don't want to accidentally allow other values of isZero beyond
(true/false) to compile as might occur if I provided a generic implementation of
MyClass and let us also suppose I am suspicious of added runtime cost from adding virtual
here for pure virtual base class methods.
This seems like such an obvious language feature that I'm likely missing the forest for the trees here and maybe I'm already getting this behavior through some mechanism and haven't realized it yet.
> cat test.cpp
#include <stdio.h>
// forward declaration of template class name
template <typename T, bool isZero> class MyClass;
// partial specialization for isZero = false case
template <typename T> class MyClass <T, false>
{
T _val;
public:
MyClass(T value) { _val = value; }
T GetValue(void) const { return _val; }
};
// partial specialization for isZero = true case
template <typename T> class MyClass <T, true>
{
public:
MyClass(T value) {}
T GetValue(void) const {return T(0);}
};
int main( void )
{
MyClass<float, false> one(1);
MyClass<float, true> notOne(1);
printf( "%f, %f\n", one.GetValue(), notOne.GetValue());
return 0;
}
> clang -Wall -pedantic test.cpp
> ./a.out
1.000000, 0.000000
You could make a static assertion at the point of use:
template <typename T>
class MyOtherClass
{
static_assert(std::is_same_v<decltype(MyClass<T, true >{T{}}.GetValue()), T>);
static_assert(std::is_same_v<decltype(MyClass<T, false>{T{}}.GetValue()), T>);
...
};
You could also attempt to define a traits class that defines/identifies the interface, if you find yourself making this assertion in several places.
Because you're leaving a template parameter unspecialized (namely T), the traits are a little awkward, but these might work:
// This traits class will inherit from either
// std::true_type or std::false_type.
template <template <typename, bool> S, typename T>
struct is_value_provider : std::intergral_constant<bool,
std::is_same_v<decltype(S<T, true >{T{}}.getValue()), T> &&
std::is_same_v<decltype(S<T, false>{T{}}.getValue()), T>>
{}
template <template <typename, bool> S, typename T>
using is_value_provider_v = is_value_provider::value;
// Usage examples:
static_assert(is_value_provider_v<MyClass, int>);
static_assert(is_value_provider_v<MyClass, float>);
static_assert(is_value_provider_v<MyClass, double>);
Unit tests perhaps?
With Catch2, you could use TEMPLATE_TEST_CASE_SIG to compile the same test case for different specializations. You could express the similarities between specializations using "actual code" instead of traits.
It might look something like this:
TEMPLATE_TEST_CASE_SIG(
"MyClass specialization compat",
"[myclass]",
((typename T, bool isZero), T, isZero),
(int, false), (int, true)
) {
const MyClass<T, isZero> mc{T{}};
T val{mc.GetValue()};
}
This will ensure that GetValue exists, is marked const and returns something that can be narrowed to T. You don't have to use a unit testing framework. You can just use a function template. You don't need to actually run the tests. You just need to compile them.
template <typename T, bool isZero>
void test() {
const MyClass<T, isZero> mc{T{}};
T val = mc.GetValue();
}
inline void runTests() {
test<int, false>();
test<int, true>();
}
If you want to be more thorough, you end up with the same tedium as in Nicholas's answer.
Given a template class A with a single template argument T, is it possible to only overload operators in A which are available for type T? For example:
template <typename T>
class A
{
public:
#if hasOperator(T, +=)
T& operator +=(const T &rhs)
{
mValue += rhs;
return mValue;
}
#endif
private:
T mValue;
}
int main()
{
A<int> a;
a += 8; //+= will forward to the += for the int
struct Test { /*no operators defined*/ };
A<Test> b; //+= is not implemented since Test does not implement +=
}
I'm writting a generic wrapper class that needs to behave exactly like the template type. So if T has operator +=, A will (at compile time) overload += accordingly. Yes, I could go ahead and just implement every operator in A, but then the compiler will error when T doesn't have a certain operator. At first I though template specialization might be the answer, but that would require a specialization for every type. While this could work and be a lot of typing, it wont because A needs to work with any type (not just what is specialized).
Use expression SFINAE to drop your operator+ from the overload resolution set unless T defines operator+
template <typename T>
class A
{
private:
T mValue;
public:
template<typename U=T>
auto operator +=(const U &rhs)
-> decltype(mValue += rhs)
{
mValue += rhs;
return mValue;
}
};
Live demo
I will give 3 solutions in decreasing complexity and utility. The last solution is the simplest, and least complex.
A small, if useful, metaprogramming library:
template<class...>struct types{using type=types;};
namespace details {
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply<Z,types<Ts...>,std::void_t<Z<Ts...>>> :
std::true_type
{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,types<Ts...>>;
A trait for the result of +=:
template<class Lhs, class Rhs>
using plus_equal_result = decltype(std::declval<Lhs>()+=std::declval<Rhs>());
template<class Lhs, class Rhs>
using can_plus_equal = can_apply< plus_equal_result, Lhs, Rhs >;
template<class T>
using can_self_plus_equal = can_plus_equal< T&, T const& >;
which gives us some nice traits that return true type or false type depending on if += is valid.
template<class A, class T, bool b = can_self_plus_equal<T>{}>
struct A_maybe_plus_equal {};
template<class A, class T>
struct A_maybe_plus_equal<A, T, true> {
A& self() { return *static_cast<A*>(this); }
A& operator+=( T && t )
{
self().mResult += std::move(t);
return self();
}
template<class U>
std::enable_if_t<can_plus_equal<T&,U>{},A&> operator+=( U && u )
{
self().mResult += std::forward<U>(u);
return self();
}
};
which gives us a += iff we pass true.
template <class T>
class A:
public A_maybe_plus_equal<A<T>, T>
{
friend class A_maybe_plus_equal<A<T>, T>;
public:
// nothing needed
private:
T mValue;
};
which gives you a += overload that takes a const T& or a T&& or a U&& on the right hand side if and only if T& += T const& is a valid expression.
This is the "perfect" solution, but it is complex.
Note that each operator can be done separately, so you don't have a combinatorial explosion of specializations.
Now, the there is an easier option. It has the downside that it doesn't support {} based construction on the right hand side, and under some readings of the standard it is illegal.
It is, however, still SFINAE friendly:
template <typename T>
class A {
public:
template<class U>
auto operator +=(U&&rhs)
-> decltype( (std::declval<T&>()+=std::declval<U&&>()),void(),A& )
// or std::enable_if_t<can_plus_equal<T&,U>{},A&>
{
mValue += std::forward<U>(rhs);
return *this;
}
private:
T mValue;
};
This can be folded into the above option, and give both {} and perfect forwarding syntax. I find that the T const& can be dropped if you have a template perfect forwarder.
The reason why this is technically undefined behavior is that the standard mandates that all template functions have at least one set of arguments that would render their body able to compile. In a given class instance, the template += of the above may have no such set of type arguments, which makes your program ill-formed with no diagnostic required (ie, UB).
There is another rule that member functions of template classes don't get instantiated unless called. Some argue that this other rule supersedes the one I mentioned in the last paragraph.
Another argument is that the method may be legal so long as there is some mixture of template arguments to the enclosing class(es) and to the template method itself that lead to it being instantiatable. I'd guess that this is what the standard committee intended, but I don't know how to read the standard to get this result.
This argument also applies to the plus_equal function in answer #1. That implementation need not be as simple. In addition, #1 provides {} based += syntax, which is a practical reason to use it. This concern -- that the program is technically ill-formed -- is academic, as all compilers I have used have no problems with this construct.
The paragraph three above this one gives us our final option. Do nothing.
template <typename T>
class A {
public:
A& operator +=(const T &rhs) {
mValue += rhs;
return *this;
}
private:
T mValue;
};
which means that you cannot SFINAE test that += doesn't work, but so long as you don't call += it "works". This is how vector's operator< works, for example. This is a lower "quality" solution, and cases of this in the standard library tend to be repaired over time.
However, as a first pass, this last choice is usually best. Only if you expect SFINAE requirements are the above hoops worthwhile.
Ultimately, C++1z is introducing concepts. I believe concepts will make this problem much easier, as eliminating overloads from consideration based on the type arguments of the enclosing class is a perennial problem in std.
You don't actually have to do anything. Individual member functions of a template class won't get instantiatiated until use. You say:
but then the compiler will error when T doesn't have a certain operator.
But isn't that clearer than having it error when A<T> doesn't? If you have:
template <typename T>
class A
{
public:
A& operator +=(const T &rhs)
{
mValue += rhs;
return *this;
}
A& operator-=(const T &rhs)
{
mValue -= rhs;
return *this;
}
// etc
private:
T mValue;
};
Then this will just work:
int main() {
A<int> a;
a += 8; //+= will forward to the += for the int
struct Test {
Test& operator-=(const Test& ) { return *this; }
};
A<Test> b;
b -= Test{}; // totally fine
b += Test{}; // error: no match for +=
// (operand types are 'main()::Test' and 'const main()::Test')
}
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.
Eigen3 and built-in type inter-compatibility
Hello guys. I'm stuck with the problem of writing routines which can handle both Eigen3 types (Matrixes and Arrays) and built-in types. I can best explain this with an example: let's suppose I have a Meter<Type> template class which has the ability to collect statistics during runtime.
The Type class should support the following operators:
operator=(Scalar)
operator=(Type)
operator+(Type)
operator-(Type)
operator*(Type)
operator/(Type)
operator*(Scalar)
operator/(Scalar)
Eigen3 types provides all of these operators with two exceptions: first, the operator*(Type) represents a dot-preduct if Type is some subclass of Eigen::MatrixBase and represents a coefficient-wise product if Type is some subclass of Eigen::ArrayBase. I can easily workaround this; second, neither one implements an operator=(Scalar) required for ensuring the correct initialization to zero.
I tried implementing the following functor classes to help me take care of the distinction but I can't get them to work:
some structs to handle the distrinction between built-in types and Eigen3 types:
template < class _Type > struct is_scalar : true_type {
using Scalar = _Type;
using Type = _Type;
static constexpr bool value = true;
};
template < class _Matrix >
struct is_scalar<Eigen::MatrixBase<_Matrix>> : false_type {
using Scalar = typename Matrix::Scalar;
static constexpr bool value = false;
};
template < class _Array >
struct is_scalar<Eigen::ArrayBase<_Array>> : false_type {
using Scalar = typename Array::Scalar;
static constexpr bool value = false;
};
the function implementation itself
template < class Scalar, bool is_scalar = Math::is_scalar<Scalar>::value >
struct set_const_impl;
template < class Scalar >
struct set_const_impl< Scalar, true > {
static const void run(Scalar &_x, Scalar _y) noexcept { _x = _y; }
};
template < class EigenType >
struct set_const_impl<EigenType, false> {
template < class Scalar >
static const void run(Eigen::EigenBase<EigenType> &_x, Scalar _y) noexcept {
_x.derived().setConstant(_y);
}
};
template < class Type, class Scalar > void set_const(Type &_x, Scalar _y) noexcept {
set_const_impl<Type>::run(_x, _y);
}
template < class Type > void set_zero(Type &_x) noexcept {
set_const_impl<Type>::run(_x, 0);
}
The specialized version set_const_impl<EigenType> never gets instantiated. For example, if I call
Eigen::Matrix<double, 3, 1> m1;
set_zero(m1);
I get the compiler to complain at the 0 on the line
set_const_impl<Type>::run(_x, 0);
saying that 0 is not implicitly convertible to Eigen::Matrix<double, 3, 1>, which means it picked the set_const_impl<Scalar, true> version of the functor (where both arguments share a the common type Scalar). This also means that my is_scalar construction isn't working in this case, even if I've already used it and tested it on other classes without problems.
I need this behaviour in several other classes and I don't want to explicitly specialize each one of them! Anyone knows what should I do to fix this?
Thanks in advance for any help!
Your problem is your traits is_scalar which takes only base classes and not derived classes.
You may try something like:
namespace Helper
{
template <typename T> std::false_type is_scalar(const Eigen::MatrixBase<T>*);
template <typename T> std::false_type is_scalar(const Eigen::ArrayBase<T>*);
std::true_type is_scalar(...);
}
template<typename T>
struct is_scalar : decltype(Helper::is_scalar(std::declval<T*>()))
{};
I encounted the same problem, and tried to solve it with C++17. Here is my solution.
template<typename Derived>
constexpr bool is_eigen_type_f(const EigenBase<Derived> *) {
return true;
}
constexpr bool is_eigen_type_f(const void *) {
return false;
}
template<typename T>
constexpr bool is_eigen_type = is_eigen_type_f(reinterpret_cast<T *>(NULL));
#Jarod42
Thank you, your suggestion has brought some light but I found another option which I think will be pretty solid: I found an implementation of is_scalar<Type> in the namespace std::__1. Now my code reads
template < class Type, bool _is_scalar = std::__1::is_scalar<Type>::value > struct is_scalar;
template < class Type >
struct is_scalar<Type, true> : true_type {
using Scalar = Type;
};
template < class Type >
struct is_scalar<Type, false> : false_type {
using Scalar = typename Type::Scalar;
};
and I am correctly able to distinguish built-in and Eigen types! Thank you anyway!
Edit:
By looking at the source code of std::__1::is_scalar I also note that this solution might stand for any kind of container object as long as it provides a type Scalar which is
an arithmetic type OR
a member pointer OR
a pointer OR
a null pointer OR
an enumeration constant
Am I correct?
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.