Is there an easy way to do the following with C++11 & Boost:
use the standard definitions of std::hash whenever available from <functional>
use boost::hash_value to define std::hash in those cases where std::hash is missing but boost::hash_value is available in <boost/functional/hash.hpp>.
For example:
std::hash<std::vector<bool>> should come from the standard library,
std::hash<std::vector<unsigned>> should be implemented with boost::hash_value.
The first idea that comes to mind is to use SFINAE and try std::hash<> if possible and otherwise use boost::hash_value(), like this:
#include <string>
#include <functional>
#include <type_traits>
#include <boost/functional/hash.hpp>
struct my_struct_0 {
std::string s;
};
template <typename T>
struct has_std_hash_subst { typedef void type; };
template <typename T, typename C = void>
struct has_std_hash : std::false_type {};
template <typename T>
struct has_std_hash<
T,
typename has_std_hash_subst<decltype( std::hash<T>()(T()) ) >::type
> : std::true_type {};
template <typename T>
static typename std::enable_if<has_std_hash<T>::value, size_t>::type
make_hash(const T &v)
{
return std::hash<T>()(v);
}
template <typename T>
static typename std::enable_if<(!has_std_hash<T>::value), size_t>::type
make_hash(const T &v)
{
return boost::hash_value(v);
}
int main()
{
make_hash(std::string("Hello, World!"));
make_hash(my_struct_0({ "Hello, World!" }));
}
Unfortunately, there is always a default specialization of std::hash that triggers static_assert failure. This may not be the case with other libraries but it is the case with GCC 4.7.2 (see bits/functional_hash.h:60):
/// Primary class template hash.
template<typename _Tp>
struct hash : public __hash_base<size_t, _Tp>
{
static_assert(sizeof(_Tp) < 0,
"std::hash is not specialized for this type");
size_t operator()(const _Tp&) const noexcept;
};
So the above SFINAE approach doesn't work — static_assert in there is a show-stopper. Therefore, you cannot really determine when std::hash is available.
Now, this does not really answer your question but might come handy — it is possible to do this trick the other way around — check for Boost implementation first and only then fall back to std::hash<>. Consider the below example that uses boost::hash_value() if it is available (i.e. for std::string and my_struct_0) and otherwise uses std::hash<> (i.e. for my_struct_1):
#include <string>
#include <functional>
#include <type_traits>
#include <boost/functional/hash.hpp>
struct my_struct_0 {
std::string s;
};
struct my_struct_1 {
std::string s;
};
namespace boost {
size_t hash_value(const my_struct_0 &v) {
return boost::hash_value(v.s);
}
}
namespace std {
template <>
struct hash<my_struct_1> {
size_t operator()(const my_struct_1 &v) const {
return std::hash<std::string>()(v.s);
}
};
}
template <typename T>
struct has_boost_hash_subst { typedef void type; };
template <typename T, typename C = void>
struct has_boost_hash : std::false_type {};
template <typename T>
struct has_boost_hash<
T,
typename has_boost_hash_subst<decltype(boost::hash_value(T()))>::type
> : std::true_type {};
template <typename T>
static typename std::enable_if<has_boost_hash<T>::value, size_t>::type
make_hash(const T &v)
{
size_t ret = boost::hash_value(v);
std::cout << "boost::hash_value(" << typeid(T).name()
<< ") = " << ret << '\n';
return ret;
}
template <typename T>
static typename std::enable_if<(!has_boost_hash<T>::value), size_t>::type
make_hash(const T &v)
{
size_t ret = std::hash<T>()(v);
std::cout << "std::hash(" << typeid(T).name()
<< ") = " << ret << '\n';
return ret;
}
int main()
{
make_hash(std::string("Hello, World!"));
make_hash(my_struct_0({ "Hello, World!" }));
make_hash(my_struct_1({ "Hello, World!" }));
}
Hope it helps.
UPDATE: Perhaps you could use the hack described here as pointed out by #ChristianRau and make the first SFINAE approach work! Though it is very dirty :)
My answer might not be correct, but I will try to explain why I think that the answer is no.
I don't think that std::hash<T> and boost:hash<T> can be used interchangeably, so I've tried hiding object creation (even if this is not perfect solution), and return their result, which is size_t. Method should be of course chosen at compile time, so function dispatch is what comes to my mind, sample code:
template <typename T>
size_t createHash(const T& t, false_type)
{
return boost::hash<T>()(t);
}
template <typename T>
size_t createHash(const T& t, true_type)
{
return std::hash<T>()(t);
}
template<typename T>
size_t createHash(const T& t)
{
return createHash<T>(t, std::is_XXX<T>::type());
}
int main()
{
vector<unsigned> v; v.push_back(1);
auto h1 = createHash(v);
cout << " hash: " << h1;
//hash<vector<unsigned> > h2;
}
The idea of this code is simple: if you can construct type of type std::hash<T>, choose second implementation, if not - choose first one.
If the first implementation is chosen, code compiles without a problem, you can check it by using fe. std::is_array<T>::type() in a wrapper function, which is of course not true, so boost::hash implementation will be choosed. However, if you use a trait which will return true_t for a vector<unsigned>, like fe. std::is_class<T>::type() then the compiler will report "C++ Standard doesn't provide...", which is a result of a static_assert.
For this to work, we would need to force compiler to return true_t if a type is really constructible (it doesn't fail static_assert) and false_t if it doesn't. However, I don't think there is a possibility to do that.
Related
Consider this function:
template<typename T>
void f(T c) {
std::cout<<c<<std::endl;
}
You see that it will not compile for types which does not have an operator<< overload.
Now I want to write a function that acts like a fallback for this case.
/*Fallback*/
template<>
void f(T c) {
std::cout<<"Not Printing"<<std::endl;
}
How must this function be defined to do the job?
Pre-C++20
To have these overloads work in a fallback way, we can start by defining a trait that detects the validity of the expression involving operator <<
namespace detail {
template<typename T, typename = void>
struct streamable : std::false_type{};
template<typename T>
struct streamable<T, decltype(std::declval<std::ostream&>() << std::declval<T&>(), void())> : std::true_type {};
}
It's just your typical use of the detection idiom with as little extra library support as possible. Depending on the standard you are building against, this may be written in other ways (for instance std::void_t can be used, if available).
Now, the two overloads can be specified rather simply:
template<typename T>
auto f(T c) -> std::enable_if_t<detail::streamable<T>::value, void> {
std::cout<<c<<std::endl;
}
template<typename T>
auto f(T c) -> std::enable_if_t<!detail::streamable<T>::value, void> {
/// other code
}
Post C++20, concepts and constraints make it a whole lot easier. It can even be written ad-hoc:
template<typename T>
requires requires(std::ostream& os, T& c) { os << c; }
void f(T c) {
std::cout<<c<<std::endl;
}
template<typename T> // No extra step, subsumed by the above when possible
void f(T c) {
// other code
}
With concepts (C++20), we can achieve this like so:
template<typename T>
concept Streamable = requires(T t){std::declval<std::ostream&>() << t; };
template<Streamable T>
void f(T c) { std::cout << c << std::endl; }
/*Fallback*/
template<typename T>
void f(T c) { std::cout << "fallback" < <std::endl; }
Demo
Test:
struct Foo{};
int main()
{
Foo foo;
f(foo); // prints "fallback"
int a = 42;
f(a); // prints "42"
}
If you want to make doubly sure that your fallback will only happen if your type is not Streamable, you can constrain it, too:
template<typename T> requires (!Streamable<T>)
void f(T c) { /*...*/ }
You have several options of doing this. Arguably the most elegant way is to define your own type trait (similar to the ones in type_traits).
Let's define a is_streamable type trait. It takes two template arguments: S is the data type of the file stream (e.g. std::ostream or std::fstream or any other type that defines a custom streaming operator that is compatible with T) and secondly the data type of the object to be streamed into this file stream T:
template<typename S, typename T, typename = void>
struct is_streamable : std::false_type {
};
template<typename S, typename T>
struct is_streamable<S, T, decltype(std::declval<S&>() << std::declval<T&>(), void())> : std::true_type {
};
So far this type trait compiles with C++11 and onwards. For C++14 and later we can create a convenient alias for it similar to other type traits in C++17:
template <typename S, typename T>
static constexpr is_streamable_v = is_streamable<S,T>::value;
This type trait will now be the basis for the next step which will make use of SFINAE (C++11 onwards), constexpr if (C++17 onwards) or concepts (C++20).
In C++11 you could achieve this with either by putting the different implementations into partial specialisations of the same struct and call it with a helper function:
class f_imp {
};
template <typename T>
class f_imp<T,true> {
public:
static constexpr void imp(T c) {
std::cout << "streamable: " << c << std::endl;
}
};
template <typename T>
class f_imp<T,false> {
public:
static constexpr void imp(T c) {
std::cout << "not streamable" << std::endl;
}
};
template <typename T>
void f(T c) {
return f_imp<T,is_streamable<std::ostream,T>::value>::imp(c);
}
Try it here!
Alternatively you could apply SFINAE either by adding a second input parameter or applying it to the return type:
template<typename T, typename std::enable_if<is_streamable<std::ostream,T>::value>::type* = nullptr>
void f(T t) {
std::cout << "streamable" << std::endl;
}
template<typename T, typename std::enable_if<!is_streamable<std::ostream,T>::value>::type* = nullptr>
void f(T t) {
std::cout << "not streamable" << std::endl;
}
Try it here!
In C++17 you can actually use a constexpr if to avoid adding a second template argument and overloading of the function altogether. You can insert all the code inside the function and use if constexpr in combination with std::is_same_v and our is_streamable_v to decide at compile time which branch of our code each template type should take. This is in particular convenient if adding two specialisations would result in duplicate code but it might be harder to read.
template<typename T>
void f(T c) {
if constexpr (is_streamable_v<std::ostream,T>) {
std::cout << "streamable:" << c << std::endl;
} else {
// Fallback
std::cerr << "not streamable" << std::endl;
}
return;
}
Try it here!
Finally in C++20 you could use this type trait to define a concepts such as streamable and not_streamable:
template <typename T>
concept streamable = is_streamable_v<std::ostream,T>;
template <typename T>
concept not_streamable = !streamable<T>;
Then you can go on to apply them to your two overloads of the functions
template <streamable T>
void f(T c) {
std::cout << "streamable: " << c << std::endl;
}
template <not_streamable T>
void f(T c) {
std::cout << "not streamable" << std::endl;
}
Try it here!
Be aware that you will have to also apply the same logic to any custom streaming operator of a templated class, e.g. of a templated vector. Instead of declaring the operator for any template parameter typename T you would have to only declare it for streamable element types only. In C++20 for example with said streamable concept:
template <streamable T>
std::ostream& operator << (std::ostream& os, std::vector<T> const& vec) {
for (auto const& v: vec) {
os << v << " ";
}
return os;
}
Otherwise - as the template argument to the is_streamable operator is std::vector<T> as a whole - the compiler sees the operator << for std::vector<T> without checking if it would result in a compilation error for an unstreamable type T which does not define the operator << itself.
Try it here!
I have a lot of code that currently works with dynamic size vectors (such as std::vector, Eigen::VectorXd, ...) and I would like it to work also with static size vectors (such as std::array, Eigen::Vector3d, ...). My code is templatized with respect to TVector in such a way that it assumes that TVector has just size and operator[]. But the big problem is construction.
There are no common grounds when it comes to construction of both static and dynamic vectors. I have decided to replace all calls to the constructor of TVector by the following hypothetical function:
template <typename TVector>
TVector createVector(std::size_t sizeAtInitialization)
{
if (TVector has constructor taking an integral type)
return TVector(sizeAtInitialization);
else
return TVector(); // sizeAtInitialization ignored
}
Such that a generic call to createVector<TVector> will become createVector<std::vector<double>>(3) or createVector<std::array<double, 3>>(3).
std::is_default_constructible will not help me here, since both vector types are default constructible.
However, I am not sure that such a thing is even possible.
I have studied the static if here and member function detection here. It all seems extremely complicated and since the static_if uses lambdas which must return to an intermediate result, which must already be constructed, I am not sure it leads anywhere.
You can use std::is_constructible together with a bit of sfinae and std::enable_if
using namespace std;
template <class T>
using IntegerConstructible =
typename enable_if<is_constructible<T, int>::value, T>::type;
template <class T>
using NotIntegerConstructible =
typename enable_if<!is_constructible<T, int>::value, T>::type;
template<class T>
auto createVector(int size)
-> IntegerConstructible<T> {
return {size};
}
template<class T>
auto createVector(int size)
-> NotIntegerConstructible<T>{
return {};
}
int main(){
auto x = createVector<std::vector<int>>(3);
auto y = createVector<std::array<int,3>>(3);
return 0;
}
IntegerConstructible and NotIntegerConstructible are alias templates which are defined as long as the template argument can (or can't) be constructed. When defined
IntegerConstructible<T> = T.
So only one of the two createVector functions has a valid return type, the other one cannot be called. This allows the compiler to choose the right overload.
I love SFINAE (+1 for Tim) but I think that tag-dispatcing is clearer for this type of problem
#include <array>
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
T cVH (int size, std::true_type const &)
{ std::cout << "with size" << std::endl; return { size }; }
template <typename T>
T cVH (int, std::false_type const &)
{ std::cout << "without size" << std::endl; return { }; }
template <typename T>
T createVector (int size)
{ return cVH<T>(size, typename std::is_constructible<T, int>::type{}); }
int main()
{
auto x = createVector<std::vector<int>>(3); // print "with size"
auto y = createVector<std::array<int,3>>(3); // print "without size"
}
--- EDIT ---
If there isn't a type-traits that can select the right value for all your tyes, you can create one yourself as (struct withSize) follows
#include <array>
#include <vector>
#include <iostream>
#include <type_traits>
template <typename>
struct withSize;
template <typename T>
struct withSize<std::vector<T>>
{ using type = std::true_type; };
template <typename T, std::size_t N>
struct withSize<std::array<T, N>>
{ using type = std::false_type; };
// others specializations of withSize for Eigen::Vector3d, Eigen::Matrix, etc.
template <typename T>
T cVH (int size, std::true_type const &)
{ std::cout << "with size" << std::endl; return { size }; }
template <typename T>
T cVH (int, std::false_type const &)
{ std::cout << "without size" << std::endl; return { }; }
template <typename T>
T createVector (int size)
{ return cVH<T>(size, typename withSize<T>::type{}); }
int main()
{
auto x = createVector<std::vector<int>>(3); // print "with size"
auto y = createVector<std::array<int,3>>(3); // print "without size"
}
I've seen types that have corresponding to_string() function, but haven't overloaded operator<<(). So, when inserting to stream, one has to << to_string(x) which is verbose. I'm wondering whether it's possible to write a generic function that users operator<<() if supported and falls back to << to_string() if not.
SFINAE is overkill, use ADL.
The trick is to make sure that an operator<< is available, not necessarily the one supplied by the type definition:
namespace helper {
template<typename T> std::ostream& operator<<(std::ostream& os, T const& t)
{
return os << to_string(t);
}
}
using helper::operator<<;
std::cout << myFoo;
This trick is commonly used in generic code which needs to choose between std::swap<T> and a specialized Foo::swap(Foo::Bar&, Foo::Bar&).
Try
template <typename T>
void print_out(T t) {
print_out_impl(std::cout, t, 0);
}
template <typename OS, typename T>
void print_out_impl(OS& o, T t,
typename std::decay<decltype(
std::declval<OS&>() << std::declval<T>()
)>::type*) {
o << t;
}
template <typename OS, typename T>
void print_out_impl(OS& o, T t, ...) {
o << t.to_string();
}
LIVE
Yes, it is possible.
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>
struct streamy
{
};
std::ostream&
operator<<(std::ostream& os, const streamy& obj)
{
return os << "streamy [" << static_cast<const void *>(&obj) << "]";
}
struct stringy
{
};
std::string
to_string(const stringy& obj)
{
auto oss = std::ostringstream {};
oss << "stringy [" << static_cast<const void *>(&obj) << "]";
return oss.str();
}
template <typename T>
std::enable_if_t
<
std::is_same
<
std::string,
decltype(to_string(std::declval<const T&>()))
>::value,
std::ostream
>&
operator<<(std::ostream& os, const T& obj)
{
return os << to_string(obj);
}
int
main()
{
std::cout << streamy {} << '\n';
std::cout << stringy {} << '\n';
}
The generic operator<< will only be available if the expression to_string(obj) is well-typed for obj a const T& and has a result of type std::string. As you have already conjectured in your comment, this is indeed SFINAE at work. If the decltype expression is not well-formed, we will get a substitution failure and the overload will disappear.
However, this will likely get you into troubles with ambiguous overloads. At the very least, put your fallback operator<< into its own namespace and only drag it in locally via a using declaration when needed. I think you will be better off writing a named function that does the same thing.
namespace detail
{
enum class out_methods { directly, to_string, member_str, not_at_all };
template <out_methods> struct tag {};
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::directly>)
{
os << arg;
}
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::to_string>)
{
os << to_string(arg);
}
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::member_str>)
{
os << arg.str();
}
template <typename T>
void
out(std::ostream&, const T&, const tag<out_methods::not_at_all>)
{
// This function will never be called but we provide it anyway such that
// we get better error messages.
throw std::logic_error {};
}
template <typename T, typename = void>
struct can_directly : std::false_type {};
template <typename T>
struct can_directly
<
T,
decltype((void) (std::declval<std::ostream&>() << std::declval<const T&>()))
> : std::true_type {};
template <typename T, typename = void>
struct can_to_string : std::false_type {};
template <typename T>
struct can_to_string
<
T,
decltype((void) (std::declval<std::ostream&>() << to_string(std::declval<const T&>())))
> : std::true_type {};
template <typename T, typename = void>
struct can_member_str : std::false_type {};
template <typename T>
struct can_member_str
<
T,
decltype((void) (std::declval<std::ostream&>() << std::declval<const T&>().str()))
> : std::true_type {};
template <typename T>
constexpr out_methods
decide_how() noexcept
{
if (can_directly<T>::value)
return out_methods::directly;
else if (can_to_string<T>::value)
return out_methods::to_string;
else if (can_member_str<T>::value)
return out_methods::member_str;
else
return out_methods::not_at_all;
}
template <typename T>
void
out(std::ostream& os, const T& arg)
{
constexpr auto how = decide_how<T>();
static_assert(how != out_methods::not_at_all, "cannot format type");
out(os, arg, tag<how> {});
}
}
template <typename... Ts>
void
out(std::ostream& os, const Ts&... args)
{
const int dummy[] = {0, ((void) detail::out(os, args), 0)...};
(void) dummy;
}
Then use it like so.
int
main()
{
std::ostringstream nl {"\n"}; // has `str` member
out(std::cout, streamy {}, nl, stringy {}, '\n');
}
The function decide_how gives you full flexibility in deciding how to output a given type, even if there are multiple options available. It is also easy to extend. For example, some types have a str member function instead of an ADL find-able to_string free function. (Actually, I already did that.)
The function detail::out uses tag dispatching to select the appropriate output method.
The can_HOW predicates are implemented using the void_t trick which I find very elegant.
The variadic out function uses the “for each argument” trick, which I find even more elegant.
Note that the code is C++14 and will require an up-to-date compiler.
Based on the answer of #MSalters (credits goes to him), this one solves my problem and should make a complete answer.
#include <iostream>
#include <string>
#include <type_traits>
struct foo_t {};
std::string to_string(foo_t) {
return "foo_t";
}
template <class CharT, class Traits, class T>
typename std::enable_if<std::is_same<CharT, char>::value,
std::basic_ostream<CharT, Traits>&>::type
operator<<(std::basic_ostream<CharT, Traits>& os, const T& x) {
return os << to_string(x);
}
int main() {
std::cout << std::string{"123"} << std::endl;
std::cout << foo_t{} << std::endl;
}
Consider the following:
template<typename T>
struct S
{
typedef M< &T::foo > MT;
}
This would work for:
S<Widget> SW;
where Widget::foo() is some function
How would I modify the definition of struct S to allow the following instead:
S<Widget*> SWP;
What you need is the following type transformation.
given T, return T
given T *, return T
It so happens that the standard library already has implemented this for us in std::remove_pointer (though it's not hard to do yourself).
With this, you can then write
using object_type = std::remove_pointer_t<T>;
using return_type = /* whatever foo returns */;
using MT = M<object_type, return_type, &object_type::foo>;
Regarding your comment that you also want to work with smart pointers, we have to re-define the type transformation.
given a smart pointer type smart_ptr<T>, return smart_ptr<T>::element_type, which should be T
given a pointer type T *, return T
otherwise, given T, return T itself
For this, we'll have to code our own meta-function. At least, I'm not aware of anything in the standard library that would help here.
We start by defining the primary template (the “otherwise” case).
template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };
The second (anonymous) type parameter that is defaulted to void will be of use later.
For (raw) pointers, we provide the following partial specialization.
template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };
If we'd stop here, we'd basically get std::remove_pointer. But we'll add an additional partial specialization for smart pointers. Of course, we'll first have to define what a “smart pointer” is. For the purpose of this example, we'll treat every type with a nested typedef named element_type as a smart pointer. Adjust this definition as you see fit.
template <typename T>
struct unwrap_obect_type
<
T,
std::conditional_t<false, typename T::element_type, void>
>
{
using type = typename T::element_type;
};
The second type parameter std::conditional_t<false, typename T::element_type, void> is a convoluted way to simulate std::void_t in C++14. The idea is that we have the following partial type function.
given a type T with a nested typedef named element_type, return void
otherwise, trigger a substitution failure
Therefore, if we are dealing with a smart pointer, we'll get a better match than the primary template and otherwise, SFINAE will remove this partial specialization from further consideration.
Here is a working example. T.C. has suggested using std::mem_fn to invoke the member function. This makes the code a lot cleaner than my initial example.
#include <cstddef>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
template <typename ObjT, typename RetT, RetT (ObjT::*Pmf)() const noexcept>
struct M
{
template <typename ThingT>
static RetT
call(ThingT&& thing) noexcept
{
auto wrapper = std::mem_fn(Pmf);
return wrapper(std::forward<ThingT>(thing));
}
};
template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };
template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };
template <typename T>
struct unwrap_obect_type<T, std::conditional_t<false, typename T::element_type, void>> { using type = typename T::element_type; };
template <typename T>
struct S
{
template <typename ThingT>
void
operator()(ThingT&& thing) const noexcept
{
using object_type = typename unwrap_obect_type<T>::type;
using id_caller_type = M<object_type, int, &object_type::id>;
using name_caller_type = M<object_type, const std::string&, &object_type::name>;
using name_length_caller_type = M<object_type, std::size_t, &object_type::name_length>;
std::cout << "id: " << id_caller_type::call(thing) << "\n";
std::cout << "name: " << name_caller_type::call(thing) << "\n";
std::cout << "name_length: " << name_length_caller_type::call(thing) << "\n";
}
};
class employee final
{
private:
int id_ {};
std::string name_ {};
public:
employee(int id, std::string name) : id_ {id}, name_ {std::move(name)}
{
}
int id() const noexcept { return this->id_; }
const std::string& name() const noexcept { return this->name_; }
std::size_t name_length() const noexcept { return this->name_.length(); }
};
int
main()
{
const auto bob = std::make_shared<employee>(100, "Smart Bob");
const auto s_object = S<employee> {};
const auto s_pointer = S<employee *> {};
const auto s_smart_pointer = S<std::shared_ptr<employee>> {};
s_object(*bob);
std::cout << "\n";
s_pointer(bob.get());
std::cout << "\n";
s_smart_pointer(bob);
}
Is there a way, presumably using templates, macros or a combination of the two, that I can generically apply a function to different classes of objects but have them respond in different ways if they do not have a specific function?
I specifically want to apply a function which will output the size of the object (i.e. the number of objects in a collection) if the object has that function but will output a simple replacement (such as "N/A") if the object doesn't. I.e.
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
I expect that this might be something similar to a static assertion although I'd clearly want to compile a different code path rather than fail at build stage.
From what I understand, you want to have a generic test to see if a class has a certain member function. This can be accomplished in C++ using SFINAE. In C++11 it's pretty simple, since you can use decltype:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
If you use C++03 it is a bit harder due to the lack of decltype, so you have to abuse sizeof instead:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Of course this uses Boost.Enable_If, which might be an unwanted (and unnecessary) dependency. However writing enable_if yourself is dead simple:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
In both cases the method signature test<U>(int) is only visible, if U has a size method, since otherwise evaluating either the decltype or the sizeof (depending on which version you use) will fail, which will then remove the method from consideration (due to SFINAE. The lengthy expressions std::declval<U>().size(), void(), std::true_type() is an abuse of C++ comma operator, which will return the last expression from the comma-separated list, so this makes sure the type is known as std::true_type for the C++11 variant (and the sizeof evaluates int for the C++03 variant). The void() in the middle is only there to make sure there are no strange overloads of the comma operator interfering with the evaluation.
Of course this will return true if T has a size method which is callable without arguments, but gives no guarantees about the return value. I assume wou probably want to detect only those methods which don't return void. This can be easily accomplished with a slight modification of the test(int) method:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
There was a discussion about the abilities of constexpr some times ago. It's time to use it I think :)
It is easy to design a trait with constexpr and decltype:
template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }
template <typename T>
constexpr bool has_size(...) { return false; }
So easy in fact that the trait loses most of its value:
#include <iostream>
#include <vector>
template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
std::cout << t.size() << "\n";
}
void print_size(...) { std::cout << "N/A\n"; }
int main() {
print_size(std::vector<int>{1, 2, 3});
print_size(1);
}
In action:
3
N/A
This can be done using a technique called SFINAE. In your specific case you could implement that using Boost.Concept Check. You'd have to write your own concept for checking for a size-method. Alternatively you could use an existing concept such as Container, which, among others, requires a size-method.
You can do something like
template< typename T>
int getSize(const T& t)
{
return -1;
}
template< typename T>
int getSize( const std::vector<T>& t)
{
return t.size();
}
template< typename T , typename U>
int getSize( const std::map<T,U>& t)
{
return t.size();
}
//Implement this interface for
//other objects
class ISupportsGetSize
{
public:
virtual int size() const= 0;
};
int getSize( const ISupportsGetSize & t )
{
return t.size();
}
int main()
{
int s = getSize( 4 );
std::vector<int> v;
s = getSize( v );
return 0;
}
basically the most generic implementation is always return -1 or "NA" but for vector and maps it will return the size. As the most general one always matches there is never a build time failure
Here you go. Replace std::cout with the output of your liking.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
You could try something like:
#include <iostream>
#include <vector>
template<typename T>
struct has_size
{
typedef char one;
typedef struct { char a[2]; } two;
template<typename Sig>
struct select
{
};
template<typename U>
static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0);
static two check (...);
static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0)));
};
struct A{ };
int main ( )
{
std::cout << has_size<int>::value << "\n";
std::cout << has_size<A>::value << "\n";
std::cout << has_size<std::vector<int>>::value << "\n";
}
but you have to be careful, this does neither work when size is overloaded, nor when it is a template. When you can use C++11, you can replace the above sizeof trick by decltype magic