C++ STL fails to find comparator for nested class - c++

I expected this code to work, but it fails to compile with GCC. It does compile if you lift the inner class out.
#include <algorithm>
template <typename T>
struct Outer
{
struct Inner
{
int x;
};
Inner vec[3];
};
template <typename T>
bool operator <(const typename Outer<T>::Inner& lhs, const typename Outer<T>::Inner& rhs)
{
return lhs.x < rhs.x;
}
int main()
{
Outer<int> out;
Outer<int>::Inner in;
std::lower_bound(out.vec, out.vec + 3, in);
}
GCC 4.4 has this to say:
...
bits/stl_algo.h:2442: error: no match for ‘operator<’ in ‘* __middle < __val’
GCC 4.7 prints a lot more stuff, including the above, ending with this:
...
bits/stl_algobase.h:957:4: note: couldn't deduce template parameter ‘T’
I'm willing to believe it's not well-formed C++, but why not?

The problem as you mentioned is that the compiler couldn't deduce template parameter T. That is because typename Outer::Inner is a nondeduced context context for T.
When a template parameter is used only in a nondeduced context, it's not taken into consideration for template argument deduction. The details are at section 14.8.2.4 of the C++ Standard (2003).
Why? If you specialize Outer as:
template <>
struct Outer<int>
{
struct Inner
{
double y;
};
Inner vec[3];
};
There is no way for the compiler to deduce if Outer::Inner should reference this definition or the previous one.
Now, onto solutions. There are a couple of possible resolutions:
Move the operator< inside Inner and make it a friend function.
Define operator< inside Inner like M M. suggested.
Suggested by Johannes Schaub - litb: Derive inner from a CRTP base parameterized by inner. Then make the parameter type the CRTP class and cast the parameter reference to the derived inner class, the type of which is given by the template argument you deduce.
I tried out the CRTP approach since it sounds so cool!:
template <typename Inner>
struct Base
{
};
template <typename T>
struct Outer
{
struct Inner : Base<Inner>
{
T x;
};
Inner vec[3];
};
template <typename T>
bool operator< (const Base<T>& lhs, const Base<T>& rhs)
{
return static_cast<const T&>(lhs).x < static_cast<const T&>(rhs).x;
}
Related answers: 1, 2, 3

Here's another workaround.
Why don't you use a custom comparer?
template <typename T>
struct Comparer
{
bool operator()(const typename Outer<T>::Inner& lhs, const typename Outer<T>::Inner& rhs)
{
return lhs.x < rhs.x;
}
};
int main()
{
Outer<int> out;
Outer<int>::Inner in;
std::lower_bound(out.vec, out.vec + 3, in, Comparer<int>());
}
Hope this works for you.

If you overload a specific operator< for int the problem will vanish:
bool operator<(const typename Outer<int>::Inner& lhs,
const typename Outer<int>::Inner& rhs)
{
return lhs.x < rhs.x;
}
The simpler solution is defining operator< inside Inner:
template<typename T>
struct Outer
{
struct Inner
{
int x;
bool operator<(const Inner& obj) const
{
return x < obj.x;
}
};
Inner vec[3];
};
Also, it's just a quick solution. And my answer is not the why compiler can not find operator< in nested situation in template mode.

Mar0ux's answer is pretty good. You can find additional information here:
Stephan T. Lavavej: Core C++, 2 of n
You should watch the whole video series - it contains a lot of useful information but you might start from minute 34 or so to get your question answered. Stephen mentions one basic rule to keep in mind:
:: is a brick wall for template argument deduction, i.e. a template argument T on the left side can't be deduced.

Related

Only overload operator if template argument does

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')
}

C++ templates: conditionally enabled member function

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.

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 to overload free function for member type of template

I have a template class that defines some member types. It's similar to how std::map defines it's value_type based on it's own template arguments, but in my case the type is more complex, so it's defined as nested class.
Now for debugging I would like to define operator<< for that type. But the compiler tells me it can't deduce the template parameters of the outer template.
My real code is not contrived like the following example, but this contrived example demonstrates the approach I tried and how it fails:
#include <iostream>
template <typename Value> class Outer;
template <typename Value>
std::ostream &operator<<(std::ostream &, const typename Outer<Value>::Inner &);
template <typename Value>
class Outer {
public:
struct Inner {
Value x;
};
void PrintSomething(Value v) {
// the real program does something useful with the inner class, of course
Inner inner = { v };
std::cout << "Inner = " << inner << std::endl; // <---- THIS SAYS IT CAN'T FIND operator<<
};
};
template <typename Value>
std::ostream &operator<<(std::ostream &s, const typename Outer<Value>::Inner &v) {
return s << v.x;
}
int main() {
Outer<int> o;
o.PrintSomething(42);
return 0;
}
This is complete sample to reproduce the problem. The compiler (I've tried 3 of them) says there is no overload of operator<< that would take second argument of type Outer<int>::Inner. When I try the same thing with different function that does not have other overloads, it instead says C2783: could not deduce template argument for 'identifier', gcc and clang keep saying there is no overload that takes second argument Outer<int>::Inner).
So is there a way to define operator<< taking Outer<Value>::Inner for any Value as it's right (so it can't be defined as member) argument?
Note: I need it to compile in several compilers and some of them don't have any C++11 features, so I need it to be C++03.
What you have there is a so-called non-deducible context. How could Value ever be deduced? You can partially specialize class templates, making it practically impossible for the compiler to even try and test every possible instantiation (of which there are.. well, infinite).
There are two workarounds: Take Inner out of Outer, or make operator<< an inline friend. The latter is the usual way people go.
template<class T>
struct Outer{
struct Inner{
T value;
friend std::ostream& operator<<(std::ostream& os, Inner const& v){
return os << v.value:
}
};
// ...
};

Potential g++ template bug?

I've encountered some code which I think should compile, but doesn't. So I'm hoping some of the local standards experts here at SO can help :-).
I basically have some code which resembles this:
#include <iostream>
template <class T = int>
class A {
public:
class U {
};
public:
U f() const { return U(); }
};
// test either the work around or the code I want...
#ifndef USE_FIX
template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
#else
typedef A<int> AI;
bool operator==(const AI::U &x, int y) {
return true;
}
#endif
int main() {
A<int> a;
std::cout << (a.f() == 1) << std::endl;
}
So, to describe what is going on here. I have a class template (A) which has an internal class (U) and at least one member function which can return an instance of that internal class (f()).
Then I am attempting to create an operator== function which compares this internal type to some other type (in this case an int, but it doesn't seem to matter).
When USE_FIX is not defined I get the following error:
test.cc: In function 'int main()':
test.cc:27:25: error: no match for 'operator==' in 'a.A<T>::f [with T = int]() == 1'
Which seems odd, because I am clearly (I think) defining a templated operator== which should cover this, in fact if I just do a little of the work for the compiler (enable USE_FIX), then I no longer get an error. Unfortunately, the "fix" doesn't work generically, only for a specific instantiation of the template.
Is this supposed to work as I expected? Or is this simply not allowed?
BTW: if it matters I am using gcc 4.5.2.
The problem with const typename A<T>::U &x is that U is a dependent type and the compiler cannot deduce T from the argument (this is one of the nondeduced context).
You could, for example, have two specializations of A:
class X { };
class Y { };
class Z { };
template <> class A<X> {
public:
typedef Z U;
};
template <> class A<Y> {
public:
typedef Z U;
};
If you then call:
Z a;
a == 1;
what should the compiler deduce T as? X? Y?
One solution in this particular case is to declare operator== as a nontemplate friend inside of the class template:
template <class T = int>
class A {
public:
class U {
};
friend bool operator==(const U& x, int y) {
return true;
}
public:
U f() const { return U(); }
};
template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
Using this template, it is not permissible (or sometimes possible) to deduce the template parameter T from the type of x. It is what is known as a non-deducible context. (E.g. Somebody could specialize A for a different parameter, say double and make A<double>::U a typedef for A<int>::U.)
There is no workaround, you would have to explicitly specify the template parameter which for operator== makes for ugly syntax.
It is not allowed for rather obvious reasons. In general case there's really no way the compiler can deduce the template argument from your call to operator ==. Apparently you assumed that the nested type U uniquely defines the enclosing A specialization. That is not true, which can be illustrated by the following example with two explicit specializations of A
template <> class A<int> {
public:
class U {};
};
template <> class A<double> {
public:
typedef A<int>::U U;
};
In this case, if you call templated operator == with an argument of type A<int>::U the compiler cannot deduce template argument T for templated operator ==. Should T be int or double? There's no way to say.
In order to avoid these ambiguities such situations are called non-deduced contexts. Deducing the enclosing class template arguments from a nested type is an example of non-deduced context.