after having scrawled through several threads such as this one
SFINAE for detecting existence of non-member template function
without finding a solution, I am posting my question here. For a tiny logger class I want to surveil the amount of data logged using the << operator. When, for instance, a string is passe or an array having the .size() member function, I want to add size() number of bytes to that amount, sizeof(...) otherwise.
How can I (using VS 2010, which has very sparse C++11 support) make use of std::enable_if and std::is_member_function_pointer to reach my goal? How can I, for instance, define a function getSize() that operates as wanted?
The code below indicates what I want, but I guess I cannot define getSize twice...
Thanks a lot for help!
template<typename T,
typename = typename std::enable_if<std::is_member_function_pointer<decltype(&T::size)>::value>
>
size_t getSize(const T &p_rObj)
{
return p_rObj.size();
}
template<typename T,
typename = typename std::enable_if<!std::is_member_function_pointer<decltype(&T::size)>::value>
>
size_t getSize(const T &p_rObj)
{
return sizeof(p_rObj);
}
Addendumg/Edit: The following either does not work with VS 2010, which then expects every call of getSize(...) to have two parameters...
template<typename T>
size_t getSize(std::enable_if<std::is_member_function_pointer<decltype(&T::size)>::value>, const T &p_rObj)
{
return p_rObj.size();
}
template<typename T>
size_t getSize(std::enable_if<!std::is_member_function_pointer<decltype(&T::size)>::value>, const T &p_rObj)
{
return sizeof(p_rObj);
}
You define twice
template<typename T, typename> size_t getSize(const T &p_rObj);
And you forget ::type
and your traits is not SFINAE compatible
The traits could be implemented:
template <typename T> auto has_size_impl(int) -> decltype(std::declval<T>().size(), std::true_type{});
template <typename T> auto has_size_impl(...) -> std::false_type;
template <typename T>
using has_size = decltype(has_size_impl<T>(0));
You have to use std::enable_if
in return type, template argument or regular argument:
template<typename T>
typename std::enable_if<has_size<T>::value, std::size_t>::type
getSize(const T &p_rObj);
or
template<typename T,
typename std::enable_if<has_size<T>::value>::type* = nullptr>
std::size_t getSize(const T &p_rObj);
or
template<typename T>
std::size_t getSize(const T &p_rObj,
typename std::enable_if<has_size<T>::value>::type* = nullptr);