Reputation: 719
I want to create a container for an arbitrary type T. However, I want to add some functionality if T has a member that is header type (which I also define). If T does not have that header member, then the added functionality can just be skipped.
The added functionality might, for example, be to add a timestamp based on when an operation is performed. Here's pseudo code for what I want:
struct my_header {
timestamp_t time;
// ... etc ...
}
template <class T>
class my_container {
public:
void some_operation(T val) {
// condition evaluated at compile time
if T has a member of type my_header {
val.header.time = get_current_time();
// ... etc ...
}
// other operations, agnostic to T
}
};
of course as I have it, some_operation also has to figure out the name of the instance of my_header in class T. This requirement could be eliminated by imposing one of the following requirements for the added functionality to be used (in order from most to least preferable):
my_header
in class T must have the name header
my_header
is the first member variable in class TUsing C++11 is fine (expected in fact).
Upvotes: 4
Views: 774
Reputation: 56863
remyable's solution is not bad (+1), but it can be simplified:
#include <iostream>
#include <type_traits>
struct my_header {
int time = 0;
};
template<typename T>
using has_header = std::is_same< decltype( T::header ), my_header >;
struct foo
{
my_header header;
};
template<typename T, typename = void>
class my_container
{
public:
T val;
void foo()
{
std::cout << "other.\n";
}
};
template<typename T>
class my_container<T, typename std::enable_if<has_header<T>::value>::type>
{
public:
T val;
void foo()
{
std::cout << "time: " << val.header.time << "\n";
}
};
int main()
{
my_container<foo> c;
my_container<int> c2;
c.foo(); // time: 0
c2.foo(); // other.
}
Of course this solution still uses the requirement that the member variable is called header
is C++ does not have introspection which can iterate a type's members.
Upvotes: 1
Reputation:
Not the best solution, but I think it can work. Stolen code from How to detect whether there is a specific member variable in class?
#include <iostream>
#include <type_traits>
struct my_header {
int time;
};
// begin stolen code
template<typename T, typename V = bool>
struct has_header : std::false_type { };
template<typename T>
struct has_header<T,
typename std::enable_if<
!std::is_same<decltype(std::declval<T>().header), void>::value,
bool
>::type
> : std::true_type { };
// end stolen code
struct foo
{
my_header header;
};
template<typename, typename = void>
class my_container;
template<typename T>
class my_container<T, typename std::enable_if<has_header<T>::value>::type>
{
public:
T val;
void foo()
{
std::cout << val.header.time << "\n";
}
};
template <typename T>
class my_container<T, typename std::enable_if<!has_header<T>::value>::type>
{
public:
T val;
void foo()
{
std::cout << "other.\n";
}
};
int main()
{
my_container<foo> c;
my_container<int> c2;
c.foo(); // garbage
c2.foo(); // other.
}
Upvotes: 1