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 char
s (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==
forNotWorkingSimpleVector<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 ifoperator==
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)?