Introduction
I had encountered this problem when working with string
s. My class supports the hash code generation, but the std::string
is not, while the template algorithm benefits on it. What to do? The solution is SFINAE.
Background
SFINAE - Substitution Failure Is Not An Error.
This rule applies during overload resolution of function templates: When substituting the deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error.
This feature is used in template metaprogramming.
Using the Code
The header module itself: (I called it "FuncUtils.h"):
#ifndef FuncUtilsH
#define FuncUtilsH
#include <utility>
#define EXEC_MEMBER_PROC_IF_PRESENT(ProcName) namespace ProcName {\
void ExecIfPresent(...) throw() {}\
\
template <class C, typename... TArgs>\
void ExecIfPresent(C& obj, TArgs&... args) {\
obj.ProcName(std::forward<TArgs>(args)...);\
}\
};
#define EXEC_MEMBER_FUNC_IF_PRESENT(FuncName, DefaultValue) namespace FuncName {\
template <typename TReturnType = decltype(DefaultValue)>\
auto ExecIfPresent(...) -> TReturnType {\
return std::move(DefaultValue);\
}\
\
template <class C, typename... TArgs>\
auto ExecIfPresent(C& obj, TArgs&... args)\
-> decltype(obj.FuncName(std::forward<TArgs>(args)...))\
{\
return std::move(obj.FuncName(std::forward<TArgs>(args)...));\
}\
};
#endif // FuncUtilsH
To use it, just "instantiate" a macro, providing function name and default value (which can be a constant, a literal, a reference, a class member, etc.):
EXEC_MEMBER_FUNC_IF_PRESENT(getHashIfKnown, size_t())
Calling:
const auto hash = getHashIfKnown::ExecIfPresent(str);
Points of Interest
This module is just a small part of the library, which uses C++11 features and which I am working under now, I decided to make it a public
property.
History
Update 1
Test code for Ideone online compiler:
EXEC_MEMBER_FUNC_IF_PRESENT(getHashIfKnown, 0U);
#include<cassert>
#include<cstring>
#include<string>
#include<iostream>
int main() {
std::string str = "test str";
auto hash = getHashIfKnown::ExecIfPresent(str);
assert(!hash);
std::cout << "str: " << hash << std::endl;
struct MyStr {
MyStr(const char* str) throw() {
if(str) {
strcpy(buf, str);
len = strlen(buf);
}
}
size_t getHashIfKnown() const throw() {
size_t hash = 0U;
for(size_t idx = 0U; idx < len; ++idx) {
hash += buf[idx] * (idx + 1U);
}
return hash;
}
size_t len = 0U;
char buf[256U];
} myStr = "we don't need no water!";
hash = getHashIfKnown::ExecIfPresent(myStr);
assert(hash);
std::cout << "myStr: " << hash << std::endl;
}
Output:
str: 0
myStr: 24355
Update 2
GitHub repository link added.
Update 3
Downloadable archive is replaced with the new fixed, updated AND redesigned version 1.01.
Note that actual changes made are NOT described NOR even mentioned in the article's text (which is represented in the original version), you can see them in the GitHub repository: