c++ Templates to change constness of a function - c++

I am interested in designing a template interface where the const ness of the function and return type itself changes depending on the template parameter. I have managed to do this for the return type as follows.
template<typename T, bool canChange>
struct Changable{};
template<typename T>
struct Changable<T,true>
{
typedef T type;
};
template<typename T>
struct Changable<T,false>
{
typedef const T type;
};
template<typename T, bool canChange>
struct Data{
typedef typename Changable<T,canChange>::type DataType;
DataType m_data; //< This makes it const/non-const at compile time.
// This function will also make the return type const/non-const
// at compile time.
DataType& GetDataRef(){ return m_data;}
//However, it seems to me that I still need a second function
//with an explicit "const", which I can't seem to avoid.
DataType& GetDataRef()const{return m_data;}
};
Can I somehow avoid having two const/non-const functions here at compile time using some SFINAE magic? std::enable_if would have been ideal here but it seems to me that const is not a type and that approach may not work. Any suggestions?

Here is an example based on inheritance:
#include <type_traits>
#include <iostream>
template<typename T, bool canChange>
struct Changable { using type = const T; };
template<typename T>
struct Changable<T, true> { using type = std::decay_t<T>; };
template<typename, typename, bool>
struct Base;
template<typename D, typename T>
struct Base<D, T, true> {
using DataType = typename Changable<T, true>::type;
DataType& GetDataRef() { std::cout << "non-const" << std::endl; return static_cast<D*>(this)->m_data; }
};
template<typename D, typename T>
struct Base<D, T, false> {
using DataType = typename Changable<T, false>::type;
DataType& GetDataRef() const { std::cout << "const" << std::endl; return static_cast<const D*>(this)->m_data; }
};
template<typename T, bool canChange>
struct Data: Base<Data<T, canChange>, T, canChange> {
friend class Base<Data<T, canChange>, T, canChange>;
typename Base<Data<T, canChange>, T, canChange>::DataType m_data{};
using Base<Data<T, canChange>, T, canChange>::GetDataRef;
};
int main() {
Data<int, true> d1;
Data<int, false> d2;
d1.GetDataRef();
d2.GetDataRef();
}
As requested, Data has only one definition of the GetDataRef method.
Which one is available, the const one or the other one, depends on the value of canChange.
Note the friend declaration. It allows the base class to access to the private data members of Data.

I think I'd approach this using the templates already available in the standard library. It does not require inheritance or any custom classes.
#include <utility>
template<typename T, bool canChange>
struct Data{
using value_type = T;
using cv_type = std::conditional_t<canChange, value_type, std::add_const_t<value_type>>;
using reference = std::add_lvalue_reference_t<cv_type>;
using const_reference = std::add_lvalue_reference_t<std::add_const_t<cv_type>>;
Data(T t) : m_data(std::move(t)) {}
cv_type m_data; //< This makes it const/non-const at compile time.
// This function will also make the return type const/non-const
// at compile time.
reference GetDataRef(){ return m_data;}
//However, it seems to me that I still need a second function
//with an explicit "const", which I can't seem to avoid.
const_reference GetDataRef() const {return m_data;}
};
int main()
{
Data<int, true> d1 { 10 };
d1.m_data = 12;
const Data<int, true>& rd1 = d1;
auto& a = d1.GetDataRef();
auto& b = rd1.GetDataRef();
a = 12; // compiles fine
// b= 12; won't compile
Data<int, false> d2 { 10 };
const Data<int, false>& rd2 = d2;
auto& c = d2.GetDataRef();
auto& d = rd2.GetDataRef();
// c = 12; // won't compile
// d = 12; // won't compile
}
Now to the question:
Can I somehow avoid having two const/non-const functions here at compile time using some SFINAE magic?
You're almost answering your own question here. SFINAE requires that template arguments are considered in immediate context. Which is a complex way of saying that the expression in std::enable_if<> must depend on some template type.
Unhappily, the template type of T is known by the time the function GetDataRef is evaluated, so enable_if won't help us here.
So if we only want one version of GetDataRef we would indeed have to resort to derivation from a template type (the base class would then be evaluated in immediate context of T).
However, there is a problem even then.
consider:
Data<int, true>& x This is a reference to mutable container containing mutable data
const Data<int, true>& y This is a reference to an immutable container containing mutable data
calling x.GetDataRef() ought to return a mutable reference to an int, otherwise we'll confuse our users.
calling y.GetDataRef() should certainly return a const reference to an int, otherwise again, users may be shocked to learn that a member of a const thing is actually mutable.

Maybe something like this can solve the issue:
#include <type_traits>
#include <iostream>
template<typename T, bool canChange>
struct Changable: std::false_type { using type = const T; };
template<typename T>
struct Changable<T, true>: std::true_type { using type = std::decay_t<T>; };
template<typename T, bool canChange>
struct Data {
using DataTraits = Changable<T, canChange>;
private:
template<typename U>
std::enable_if_t<U::value, typename U::type&>
GetDataRefImpl() { std::cout << "non const" << std::endl; return m_data; }
template<typename U>
std::enable_if_t<not U::value, typename U::type&>
GetDataRefImpl() const { std::cout << "const" << std::endl; return m_data; }
public:
typename DataTraits::type m_data{};
typename DataTraits::type& GetDataRef() { return GetDataRefImpl<DataTraits>(); }
typename DataTraits::type& GetDataRef() const { return GetDataRefImpl<DataTraits>(); }
};
int main() {
Data<int, true> d1;
Data<int, false> d2;
d1.GetDataRef();
d2.GetDataRef();
}
The basic idea is to have both the functions exposed by the class, then forward them internally to the same sfinaed one that is const or non-const (this depends on the value of canChange).
As you can see by running the example, the result is:
non const
const
This is true even if both d1 and d2 have been defined as non const.
The std::enable_if turn on the right internal function at compile time.
Note that I've used what the C++14 offers (as an example std::enable_if_t).
The example can be easily converted to a C++11 based on (std::enable_if_t is nothing more than typename std::enable_if<condition, type>::type and so on).

If C++17 is available to you, have a look at is_const, add_const and remove_const.
Together with if constexpr (), a rather elegant solution should be possible.

Related

Sum types in C++

At work, I ran into a situation where the best type to describe the result returned from a function would be std::variant<uint64_t, uint64_t> - of course, this isn't valid C++, because you can't have two variants of the same type. I could represent this as a std::pair<bool, uint64_t>, or where the first element of the pair is an enum, but this is a special case; a std::variant<uint64_t, uint64_t, bool> isn't so neatly representable, and my functional programming background really made me want Either - so I went to try to implement it, using the Visitor pattern as I have been able to do in other languages without native support for sum types:
template <typename A, typename B, typename C>
class EitherVisitor {
virtual C onLeft(const A& left) = 0;
virtual C onRight(const B& right) = 0;
};
template <typename A, typename B>
class Either {
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) = 0;
};
template <typename A, typename B>
class Left: Either<A, B> {
private:
A value;
public:
Left(const A& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onLeft(value);
}
};
template <typename A, typename B>
class Right: Either<A, B> {
private:
B value;
public:
Right(const B& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onRight(value);
}
};
C++ rejects this, because the template method Accept cannot be virtual. Is there a workaround to this limitation, that would allow me to correctly represent the fundamental sum type in terms of its f-algebra and catamorphism?
Perhaps the simplest solution is a lightweight wrapper around T for Right and Left?
Basically a strong type alias (could also use Boost's strong typedef)
template<class T>
struct Left
{
T val;
};
template<class T>
struct Right
{
T val;
};
And then we can distinguish between them for visitation:
template<class T, class U>
using Either = std::variant<Left<T>, Right<U>>;
Either<int, int> TrySomething()
{
if (rand() % 2 == 0) // get off my case about rand(), I know it's bad
return Left<int>{0};
else
return Right<int>{0};
}
struct visitor
{
template<class T>
void operator()(const Left<T>& val_wrapper)
{
std::cout << "Success! Value is: " << val_wrapper.val << std::endl;
}
template<class T>
void operator()(const Right<T>& val_wrapper)
{
std::cout << "Failure! Value is: " << val_wrapper.val << std::endl;
}
};
int main()
{
visitor v;
for (size_t i = 0; i < 10; ++i)
{
auto res = TrySomething();
std::visit(v, res);
}
}
Demo
std::variant<X,X> is valid C++.
It is a bit awkward to use, because std::visit doesn't give you the index, and std::get<X> won't work either.
The way you can work around this is to create a variant-of-indexes, which is like a strong enum.
template<std::size_t i>
using index_t = std::integral_constant<std::size_t, i>;
template<std::size_t i>
constexpr index_t<i> index = {};
template<std::size_t...Is>
using number = std::variant< index_t<Is>... >;
namespace helpers {
template<class X>
struct number_helper;
template<std::size_t...Is>
struct number_helper<std::index_sequence<Is...>> {
using type=number<Is...>;
};
}
template<std::size_t N>
using alternative = typename helpers::number_helper<std::make_index_sequence<N>>::type;
we can then extract the alternative from a variant:
namespace helpers {
template<class...Ts, std::size_t...Is, class R=alternative<sizeof...(Ts)>>
constexpr R get_alternative( std::variant<Ts...> const& v, std::index_sequence<Is...> ) {
constexpr R retvals[] = {
R(index<Is>)...
};
return retvals[v.index()];
}
}
template<class...Ts>
constexpr alternative<sizeof...(Ts)> get_alternative( std::variant<Ts...> const& v )
{
return helpers::get_alternative(v, std::make_index_sequence<sizeof...(Ts)>{});
}
so now you have a std::variant<int, int>, you can
auto which = get_alternative( var );
and which is a variant, represented at runtime by an integer which is the index of the active type in var. You can:
std::variant<int, int> var( std::in_place_index_t<1>{}, 7 );
auto which = get_alternative( var );
std::visit( [&var](auto I) {
std::cout << std::get<I>(var) << "\n";
}, get_alternative(var) );
and get access to which of the alternative possibilities in var is active with a compile time constant.
The get_alternative(variant), I find, makes variant<X,X,X> much more usable, and fills in the hole I think you might be running into.
Live example.
Now if you don't need a compile-time index of which one is active, you can just call var.index(), and visit via visit( lambda, var ).
When you construct the variant, you do need the compile time index to do a variant<int, int> var( std::in_place_index_t<0>{}, 7 ). The wording is a bit awkward, because while C++ supports variants of multiples of the same type, it considers them a bit less likely than a "standard" disjoint variant outside of generic code.
But I've used this alternative and get_alternative like code to support functional programming like data glue code before.

Computing the type of a function pointer

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

How to check correctly for (const) overloaded method

I am currently trying to get the following to compile:
class foo {
};
class bar {
public:
const foo & to_foo() const {
return f;
}
foo & to_foo() {
return f;
}
private:
foo f;
};
template< typename T, typename Enable = void >
class convert {};
template< typename T >
struct convert< T, typename std::enable_if< std::is_member_function_pointer< decltype( &T::to_foo ) >::value >::type > {
static const foo & call1( const bar & b ) {
return b.to_foo();
}
static foo & call2( bar & b ) {
return b.to_foo();
}
};
However the specialisation get's confused by the presence of two possible to_foo() members, so it will choose the default case. As soon as I remove one of the to_foo() members, it works, but then one of the callX() methods fails because it does not match the constness.
Is there any way to detect this function in this case?
EDIT:
Here is an example on ideone: http://ideone.com/E6saX
When one of the the methods is removed, it works just fine: http://ideone.com/iBKoN
It is still a bit unclear to me what you are trying to achieve. I will suppose that the target type (foo) is fixed and we are not attempting to create a full bridge system.
In this case, we can ditch the structure and just rely on overload selection.
foo const& to_foo(bar const& b) { return b.to_foo(); }
foo& to_foo(bar& b) { return b.to_foo(); }
Works just fine, as far as the actual translation goes. No template involved.
Now the question might be how to actually detect whether this conversion is possible or not. In this case, we need to use SFINAE to avoid a hard-error while attempting the conversion.
#include <iostream>
#include <utility>
// Didn't remember where this is implemented, oh well
template <typename T, typename U> struct same_type: std::false_type {};
template <typename T> struct same_type<T, T>: std::true_type {};
// Types to play with
struct Foo {};
struct Bar { Foo _foo; };
struct Bad {};
Foo const& to_foo(Bar const& b) { return b._foo; }
Foo& to_foo(Bar& b) { return b._foo; }
// Checker
template <typename T>
struct ToFoo {
T const& _crt;
T& _rt;
template <typename U>
static auto to_foo_exists(U const& crt, U& rt) ->
decltype(to_foo(crt), to_foo(rt), std::true_type());
static std::false_type to_foo_exists(...);
// Work around as the following does not seem to work
// static bool const value = decltype(to_foo_exists(_crt, _rt))::value;
static bool const value = same_type<
decltype(to_foo_exists(_crt, _rt)),
std::true_type
>::value;
};
// Proof
int main() {
std::cout << ToFoo<Bar>::value << "\n"; // true
std::cout << ToFoo<Bad>::value << "\n"; // false
}
Note: successfully compiled on Clang 3.0 (with the work around) and gcc 4.5.1.
I don't know much about templates yet, but it seems that is_const is the type trait you're looking for, to check as to whether the function is const.
Link here
my gcc(4.1.0) is not support c++0x, so i remove the std::enable_if part. then it compiles and runs successfullly.
see:
http://ideone.com/KzasX
thanks

How to determine the type of a function parameter given the type of argument passed to it?

I need a type trait which will report the type of a functor's operator() parameter given the type of the functor and the type of an argument passed to it. Basically, I need to determine precisely what type the argument will be converted to when passing it to the functor. For simplicity, let's assume that I'm only interested in a (potentially templated, potentially overloaded) operator() with a single argument. Unfortunately, I'm limited to c++03. Can it be done? If not, how about c++11?
Here's one example:
#include <cassert>
#include <type_traits>
template<typename Functor, typename Argument>
struct parameter_type
{
// what goes here?
typedef ... type;
};
struct takes_float_cref
{
void operator()(const float &);
};
int main()
{
// when calling takes_float_cref::operator() with an int,
// i'd expect a conversion to const float &
assert(std::is_same(parameter_type<takes_float_cref, int>::type, const float &>::value);
return 0;
}
A related question (whose answer doesn't give me quite what I need) gives the context for needing such a trait. I've put further unit tests on ideone.
I am afraid that this is not exactly possible without help from your client.
TL;DR: unit test fail (grrr gcc).
The general case of your question is this functor:
struct Functor {
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T t) const;
void operator(double d) const;
};
It combines the two main issues here:
If there is an overload, then taking &F::operator() requires a static_cast to a given type to disambiguate which overload should be used
Templates (and arbitrary conditions to express them) cannot be succintly expressed as typedefs
Therefore, the client (Functor here) need to provide additional hooks for you if you truly wish to get this type. And without decltype I don't see how to get it (note, gcc provides typeof as an extension in C++03).
Getting the client to give us hints:
// 1. Make use of the return value:
struct Functor {
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
operator()(T t) const;
double operator(double d) const;
};
// 2. Double up the work (but leave the return value as is)
struct Functor {
template <typename T>
static typename std::enable_if<std::is_integral<T>::value, T>::type Select(T);
static double Select(T);
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T t) const;
void operator(double d) const;
};
Let's say we go for the second case (leaving the return value free for another use).
template <typename F, typename T>
struct parameter {
static T t;
typedef decltype(F::Select(t)) type;
};
In C++03, replace decltype by typeof with gcc.
I don't see a way to forego decltype. sizeof does provides an unevaluated context but it does not seem to help much here.
Unit Tests Here.
Unfortunately, there is a gcc bug it seems with the references, and float& gets reduced to float (and any other reference really), the bug remains with decltype so it's just a buggy implementation :/ Clang 3.0 has no problem with the C++11 version (decltype) but does not implement typeof I think.
This can be worked around by requiring the client to use a ref<float> class instead, and then unwrapping it. Just a bit more burden...
To get started I would go with this:
template<typename F>
struct parameter_type_impl;
// may be with variadic arguments
template<typename R, typename A, typename F>
struct parameter_type_impl<R (F::*)(A)> {
typedef A type;
};
template<typename F>
struct parameter_type {
typedef typename parameter_type_impl<decltype(&F::operator())>::type type;
};
I don't see why you would pass in the actual argument type. If the
conversion is not able to take place you have to use special measures
(e.g. SFINAE) later on. I think the two things are orthogonal:
deducing the argument type, then deciding if the argument you would
like to pass in is convertible.
The non-C++03 decltype is hard to get rid of. Specifying a function
type always requires knowledge of the arguments. As soon as you would
spell out the arguments, the whole thing would be moot.
The same problem would occur with Boost.Function Types.
#include <iostream>
template< typename PParameter00 = void, typename PParameter01 = void, typename PParameter02 = void, typename PParameter03 = void >
struct TIdentityParameter // Users need to inherit from it. Add more types as needed.
{
typedef PParameter00 TType00;
typedef PParameter01 TType01;
typedef PParameter02 TType02;
typedef PParameter03 TType03;
};
struct TUserFunctor00 : public TIdentityParameter< float const &, int, void * >
{
void operator()( float const &, int, void * );
// or they can do
//void operator()( TType00, TType01, TType02 );
};
struct TUserFunctor01 : public TIdentityParameter< char const *, double >
{
void operator()( char const*, double );
// or they can do
//void operator()( TType00, TType01 );
};
template< bool pValue >
struct TValueBool
{
static bool const sValue = pValue;
};
template< typename PType00, typename PType01 >
struct TIsSame : public TValueBool< false >
{
};
template< typename PType >
struct TIsSame< PType, PType > : public TValueBool< true >
{
};
int main( void )
{
std::cout << TIsSame< TUserFunctor00::TType02, void * >::sValue << std::endl;
std::cout << TIsSame< TUserFunctor01::TType00, double >::sValue << std::endl;
return ( 0 );
}
Code on [ideone][1]. I don't think it's asking too much from users to inherit from your struct in a pattern explained to them. After all, they want to work with your library. Anyway, maybe it's not what you are looking for.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT: Here is something, maybe, a bit closer to the functionality JAred is looking for, but, I understand, the style does not appeal to him. Although, within C++03, I don't see how you can do it differently. Note, you can make TIdentityParameter take, say 16 template arguments to cover 16 possible types. Once again, yes, user has to inherit and specify types. Ideone:
#include <iostream>
struct TOneCrazyStruct
{
};
template< typename PParameter00 = TOneCrazyStruct, typename PParameter01 = TOneCrazyStruct, typename PParameter02 = TOneCrazyStruct,
typename PParameter03 = TOneCrazyStruct, typename PParameter04 = TOneCrazyStruct >
struct TIdentityParameter //Users will need to inherit from this struct as shown below.
{
typedef PParameter00 TType00;
typedef PParameter01 TType01;
typedef PParameter02 TType02;
typedef PParameter03 TType03;
typedef PParameter04 TType04;
};
struct TUserFunctor00 : public TIdentityParameter< float const &, int, void *, double >
{
void operator()( float const &, int, void * );
void operator()( double );
};
template< bool pValue >
struct TValueBool
{
static bool const sValue = pValue;
};
template< typename PType00, typename PType01 >
struct TIsSame : public TValueBool< false >
{
};
template< typename PType >
struct TIsSame< PType, PType > : public TValueBool< true >
{
};
template< typename PFunctor, typename PParameter >
struct THasType : public TValueBool<
TIsSame< typename PFunctor::TType00, PParameter >::sValue || TIsSame< typename PFunctor::TType01, PParameter >::sValue
|| TIsSame< typename PFunctor::TType02, PParameter >::sValue || TIsSame< typename PFunctor::TType03, PParameter >::sValue >
{
};
int main( void )
{
std::cout << THasType< TUserFunctor00, void * >::sValue << std::endl;
std::cout << THasType< TUserFunctor00, long double >::sValue << std::endl;
return ( 0 );
}

Detecting a function in C++ at compile time

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