J
Juha Nieminen
I was testing the usage (or "abuse") of SFINAE for compile-time
introspection. In this particular example, I use it to call the
'reserve()' function of an object if it has it, else nothing. The
program is as follows (sorry for the somewhat lengthy program, but
I don't know if this can be implemented more briefly; please tell
me if it's possible, because it would be interesting):
//--------------------------------------------------------------------
template<typename T>
struct has_reserve_func
{
typedef char yes[1];
typedef char no[2];
template<typename size_type, void (T::*fptr)(size_type)>
struct test_struct {};
template<typename C>
static yes& test(test_struct<typename C::size_type, &C::reserve>*);
template<typename>
static no& test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
#include <iostream>
template<bool>
struct CallReserve
{
template<typename Cont_t>
static void makeCall(Cont_t&, typename Cont_t::size_type)
{
std::cout << "Not calling reserve.\n";
}
};
template<>
struct CallReserve<true>
{
template<typename Cont_t>
static void makeCall(Cont_t& container,
typename Cont_t::size_type amount)
{
std::cout << "Calling reserve.\n";
container.reserve(amount);
}
};
template<typename Cont_t>
void callReserve(Cont_t& container, typename Cont_t::size_type amount)
{
CallReserve<has_reserve_func<Cont_t>::value>::makeCall
(container, amount);
}
//--------------------------------------------------------------------
// Test
#include <vector>
#include <list>
class Test: public std::vector<int> {};
int main()
{
std::cout << "vector: ";
std::vector<int> v;
callReserve(v, 123);
std::cout << "list: ";
std::list<int> l;
callReserve(l, 123);
}
//--------------------------------------------------------------------
When run, it prints the expected:
vector: Calling reserve.
list: Not calling reserve.
However, the "introspection" fails if the 'reserve()' function is
in a base class instead of the derived class. For example if I do
this:
//--------------------------------------------------------------------
class Test: public std::vector<int> {};
int main()
{
std::cout << "Test: ";
Testi t;
callReserve(t, 123);
}
//--------------------------------------------------------------------
it will not call the reserve function.
What is the reason for this, and can it be made to work?
introspection. In this particular example, I use it to call the
'reserve()' function of an object if it has it, else nothing. The
program is as follows (sorry for the somewhat lengthy program, but
I don't know if this can be implemented more briefly; please tell
me if it's possible, because it would be interesting):
//--------------------------------------------------------------------
template<typename T>
struct has_reserve_func
{
typedef char yes[1];
typedef char no[2];
template<typename size_type, void (T::*fptr)(size_type)>
struct test_struct {};
template<typename C>
static yes& test(test_struct<typename C::size_type, &C::reserve>*);
template<typename>
static no& test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
#include <iostream>
template<bool>
struct CallReserve
{
template<typename Cont_t>
static void makeCall(Cont_t&, typename Cont_t::size_type)
{
std::cout << "Not calling reserve.\n";
}
};
template<>
struct CallReserve<true>
{
template<typename Cont_t>
static void makeCall(Cont_t& container,
typename Cont_t::size_type amount)
{
std::cout << "Calling reserve.\n";
container.reserve(amount);
}
};
template<typename Cont_t>
void callReserve(Cont_t& container, typename Cont_t::size_type amount)
{
CallReserve<has_reserve_func<Cont_t>::value>::makeCall
(container, amount);
}
//--------------------------------------------------------------------
// Test
#include <vector>
#include <list>
class Test: public std::vector<int> {};
int main()
{
std::cout << "vector: ";
std::vector<int> v;
callReserve(v, 123);
std::cout << "list: ";
std::list<int> l;
callReserve(l, 123);
}
//--------------------------------------------------------------------
When run, it prints the expected:
vector: Calling reserve.
list: Not calling reserve.
However, the "introspection" fails if the 'reserve()' function is
in a base class instead of the derived class. For example if I do
this:
//--------------------------------------------------------------------
class Test: public std::vector<int> {};
int main()
{
std::cout << "Test: ";
Testi t;
callReserve(t, 123);
}
//--------------------------------------------------------------------
it will not call the reserve function.
What is the reason for this, and can it be made to work?