I would like to ask you for help with the programming headache I face last few days. Let me try to explain what I am about to implement...
My goal is to define a set of equations with its validity. Let me explain more in detail...
I think about being each equation object a functor - a class defining the operator(). The definition of this operator should be specialized for each equation type. The specialization contains the calculation itself:
.h:
enum class IDs : int { A = 0, B = 1, C = 2 };
template<IDs WHICH>
struct Equation
{
int operator() ( void );
}
.cpp:
template<>
Equation<IDs::A>::operator()( void )
{
/* Just some sample equation */
return( 42 + 28 );
}
As you may have noticed, the specialization is defined by enum class member IDs::?.
This seems to be working. But I would like to add so called availability feature - The equation may be valid only for certain user object types.
There is 'validity group' declared:
/* Object types declaration */
namespace Objects {
using Object0 = boost::mpl::int_<0>;
using Object1 = boost::mpl::int_<1>;
using Object2 = boost::mpl::int_<2>;
}
/* Validity groups declaration */
using ValidityGroup1 = boost::mpl::vector<Object0, Object2>;
using ValidityGroup2 = boost::mpl::vector<Object1>;
I am using the following construct to make the class enabled or disabled (using boost::enable_if). Just to show how I use it:
template<typename TYPE_LIST, typename QUERY_TYPE>
struct IsTypeInList
{
using TypePos = typename boost::mpl::find<TYPE_LIST, QUERY_TYPE>::type;
using Finish = typename boost::mpl::end<TYPE_LIST>::type;
using type = typename boost::mpl::not_<boost::is_same<TypePos, Finish> >::type;
using value_type = typename type::value_type;
static const bool value = type::value;
};
template<typename OBJECT_TYPE, typename ENABLER=void>
class SampleClass;
template<typename OBJECT_TYPE>
class SampleClass<OBJECT_TYPE, typename boost::enable_if<typename IsTypeInList<ValidityGroup1, Object0>::type>::type>
{}
The partial specialization of SampleClass is available only if Object0 belongs to ValidityGroup1. So far so good. This principle is verified.
Now the funny stuff comes. I would like to merge the two things together:
THE GOAL:
Define Equation's operator() who's specialization containing valid body is defined by IDs::?? enum class value" and is available only for Object belonging to ValidityGroup... There can be another calculation of the same IDs::?? but valid for Object in other ValidityGroup (aka Object0's property is calculated some other way than for Object1)
I know the whole concept is quite complicated and may be confusing. Let me show my attempt to implement this stuff:
template<typename OBJECT_TYPE, typename VALIDITY_GROUP, IDs ID, typename ENABLER = void>
class Equation;
template<typename OBJECT_TYPE, typename VALIDITY_GROUP, IDs ID>
class Equation<OBJECT_TYPE, VALIDITY_GROUP, ID, typename boost::enable_if<typename IsTypeInList<VALIDITY_GROUP, OBJECT_TYPE>::type>::type >
: public EquationBase<IDs>
{
public:
int operator() ( void );
};
template<typename OBJECT_TYPE, typename VALIDITY_GROUP, IDs ID>
int Equation<OBJECT_TYPE, ValidityGroup1, Ids::A>::operator() ( void )
{
return( 42 + 56 );
}
But the operator() definition is not working... Could you please advise me how to make this working? Or does anyone have any other idea how to fulfill the goal written above?
Many thanks in advance to anybody willing to help me...
Cheers Martin
EDIT:
The equation is used in template class object. Let the code explain:
template<typename OBJECT_TYPE>
class Object
{
public:
Object( void );
};
.cpp:
template<typename OBJECT_TYPE>
Object<OBJECT_TYPE>::Object( void )
{
std::cout << Equation<IDs::A>()() << std::endl;
}
The problem is OBJECT_TYPE is not defined when the operators () are specialized...
If I understand correctly what you want to obtain, I suppose there are many ways.
The following is a iper-semplified example (but complete ad working) that show how to select different implementations using std::enable_if (but boost::enable_if should be OK) with the return type of the operator
#include <iostream>
#include <type_traits>
template <typename ObjT, typename ValT>
class Equation
{
public:
template <typename X = ObjT>
typename std::enable_if<true == std::is_same<X, ValT>::value, int>::type
operator() ( void )
{ return( 0 ); }
template <typename X = ObjT>
typename std::enable_if<false == std::is_same<X, ValT>::value, int>::type
operator() ( void )
{ return( 1 ); }
};
int main()
{
Equation<int, int> eq0;
Equation<int, long> eq1;
std::cout << "eq0 val: " << eq0() << std::endl; // print "eq0 val: 0"
std::cout << "eq1 val: " << eq1() << std::endl; // print "eq1 val: 1"
}
Not really elegant, I suppose.
Another solution (that, I suppose, best fits your desiderata) could be the following based on class partial specialization
#include <iostream>
#include <type_traits>
template <typename ObjT, typename ValT, bool = std::is_same<ObjT, ValT>::value>
class Equation;
template <typename ObjT, typename ValT>
class Equation<ObjT, ValT, true>
{
public:
int operator() ();
};
template <typename ObjT, typename ValT>
class Equation<ObjT, ValT, false>
{
public:
int operator() ();
};
template <typename ObjT, typename ValT>
int Equation<ObjT, ValT, true>::operator() ()
{ return( 0 ); }
template <typename ObjT, typename ValT>
int Equation<ObjT, ValT, false>::operator() ()
{ return( 1 ); }
int main()
{
Equation<int, int> eq0;
Equation<int, long> eq1;
std::cout << "eq0 val: " << eq0() << std::endl; // print "eq0 val: 0"
std::cout << "eq1 val: " << eq1() << std::endl; // print "eq1 val: 1"
}
Related
Suppose I have some class specialized for each enum type:
enum MyEnum {
EnumA = 0, EnumB, EnumSize
};
template <enum MyEnum>
class StaticEnumInfo {
};
template <>
class StaticEnumInfo<EnumA>{
typedef bool type;
const std::string name = "EnumA";
};
template <>
class StaticEnumInfo<EnumB>{
typedef int type;
const std::string name = "EnumB";
};
Is it possible to iterate over all names and print them?
I want to write something like:
for(MyEnum i = EnumA; i < EnumSize; ++i){
// Doesn't make sense, I know.
std::cout << StaticEnumInfo<i>::name << std::endl;
}
I know I can create one map somewhere else to solve this kind of mapping (for the strings, not the types...)
I don't have access to boost
Until proper expansion statements are available, you could always do this:
template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
(static_cast<void>(f(std::integral_constant<T, S>{})), ...);
}
And use it like this:
for_sequence(
std::make_integer_sequence<int, EnumSize>{},
[&](auto i) {
constexpr auto index = static_cast<MyEnum>(int{i});
std::cout << StaticEnumInfo<index>::name << std::endl;
}
);
However be careful, as it will only work if all enum member are sequential.
Live example
consider the following mixings that provide additional functionality to the BaseSensor class.
class PeakSensor{ /*...*/ };
class TroughSensor{ /*...*/ };
template<typename EdgeType> //EdgeType can be PeakSensor or TroughtSensor
class EdgeSensor : public EdgeType
{
public:
void saveEdges(){}
}
class TrendSensor
{
public:
void saveTrends(){}
}
template<typename ... SensorType>
class BaseSensor : public SensorType ... //SensorType can be TrendSensor, EdgeSensor or others...
{
public:
void saveSensor();
}
where
template<typename ... SensorType>
void BaseSensor<SensorType...>::saveSensor()
{
this->saveTrends();
this->saveEdges();
}
and main.cpp
int main(int , const char **)
{
{ //this works
BaseSensor<EdgeSensor<TroughEdge> , TrendSensor> eps;
eps.saveSensor();
cout << endl;
}
{ //this cannot not find "saveSensorEdges()", so it won't compile
BaseSensor<TrendSensor> eps;
eps.saveSensor();
cout << endl;
}
return 0;
}
I have read that solutions involve following "SFINAE" rule however, the solutions in SO involve typing code specific to checking if a member function works (for example here). Is it possible to minimize coding by checking if the mixin class (ie TrendSensor or EdgeSensor) are included?
I am searching for a solution that minimizes additional coding (ie creating a multiple line struct just to check if a single method exists) in c++11 (boost may very well be used).
If this is not possible how could I check if the function exists for a specific instance and execute it (or not) accordingly.
Basically, can anything be placed in front of
EXEC_ONLY_IF_EXISTS ( this->saveTrends(); )
EXEC_ONLY_IF_EXISTS ( this->saveEdges(); )
in order to conditionally allow the code and execute it , or remove it altogether depending on whether the mixin is part of the instantiated object.
thank you!
You can call, in saveSensor(), a couple of new method: localTrends() and localEdges().
Then, you can develop two alternative implementations (SFINAE selected) of localTrends(); the first one, that call saveTrends(), enabled only when the TrendSensor is a base class of the actual class, and the second one, that doesn't call saveTrends(), otherwise (when TrendSensor isn't a base class).
Same strategy for localEdges(): two alternative implementations (SFINAE selected), the first one, that call saveEdges(), enabled only when the EdgeSensor<Something> is a base class of the actual class, and the second one, that doesn't call saveEdges(), otherwise (when EdgeSensor<Something> isn't a base class).
The SFINAE selection for localTrends() is easy, using std::is_base_of.
The SFINAE selection for localEdges() is a little more complicated because you can't (or at least: I don't know how to) check if EdgeSensor<Something> is a base class of the actual class using std::is_base_of because I don't know the Something class that is the template argument of EdgeSensor.
So I've developed a template struct, chkTplInL (for "checkTemplateInList") that receive a "template template" argument (that is EdgeSensor without its Something template argument) and a list of typenames. This struct set a constexpr static boolean value that is true if a class based on the "template template" argument (EdgeSensor, in our case) is in the list of typenames, (that, in our case, is: if a EdgeSensor class is base of the actual SensorType class), false otherwise.
The following is a working example
#include <type_traits>
#include <iostream>
class PeakSensor { };
class TroughSensor { };
class TroughEdge { };
template<typename EdgeType>
class EdgeSensor : public EdgeType
{ public: void saveEdges(){} };
class TrendSensor
{ public: void saveTrends(){} };
template <template <typename ...> class, typename ...>
struct chkTplInL;
template <template <typename ...> class C>
struct chkTplInL<C>
{ static constexpr bool value = false; };
template <template <typename ...> class C, typename T0, typename ... Ts>
struct chkTplInL<C, T0, Ts...>
{ static constexpr bool value = chkTplInL<C, Ts...>::value; };
template <template <typename ...> class C, typename ... Ts1, typename ... Ts2>
struct chkTplInL<C, C<Ts1...>, Ts2...>
{ static constexpr bool value = true; };
template<typename ... SensorType>
class BaseSensor : public SensorType ...
{
public:
template <template <typename...> class C = EdgeSensor>
typename std::enable_if<
true == chkTplInL<C, SensorType...>::value>::type localEdges ()
{ this->saveEdges(); std::cout << "localEdges case A" << std::endl; }
template <template <typename...> class C = EdgeSensor>
typename std::enable_if<
false == chkTplInL<C, SensorType...>::value>::type localEdges ()
{ std::cout << "localEdges case B" << std::endl; }
template <typename B = TrendSensor>
typename std::enable_if<
true == std::is_base_of<B, BaseSensor>::value>::type localTrends ()
{ this->saveTrends(); std::cout << "localTrends case A" << std::endl; }
template <typename B = TrendSensor>
typename std::enable_if<
false == std::is_base_of<B, BaseSensor>::value>::type localTrends ()
{ std::cout << "localTrends case B" << std::endl; }
void saveSensor ()
{
this->localTrends();
this->localEdges();
}
};
int main ()
{
BaseSensor<EdgeSensor<TroughEdge> , TrendSensor> eps1;
eps1.saveSensor(); // print localTrends case A
// and localEdges case A
BaseSensor<TrendSensor> eps2;
eps2.saveSensor(); // print localTrends case A
// and localEdges case B
BaseSensor<EdgeSensor<TroughSensor>> eps3;
eps3.saveSensor(); // print localTrends case B
// and localEdges case A
BaseSensor<> eps4;
eps4.saveSensor(); // print localTrends case B
// and localEdges case B
return 0;
}
If you can use a C++14 compiler, you can use std::enable_if_t, so the SFINAE selection for localEdges() and localTrends() can be a little simpler
template <template <typename...> class C = EdgeSensor>
std::enable_if_t<
true == chkTplInL<C, SensorType...>::value> localEdges ()
{ this->saveEdges(); std::cout << "localEdges case A" << std::endl; }
template <template <typename...> class C = EdgeSensor>
std::enable_if_t<
false == chkTplInL<C, SensorType...>::value> localEdges ()
{ std::cout << "localEdges case B" << std::endl; }
template <typename B = TrendSensor>
std::enable_if_t<
true == std::is_base_of<B, BaseSensor>::value> localTrends ()
{ this->saveTrends(); std::cout << "localTrends case A" << std::endl; }
template <typename B = TrendSensor>
std::enable_if_t<
false == std::is_base_of<B, BaseSensor>::value> localTrends ()
{ std::cout << "localTrends case B" << 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);
}
I have a template class where each template argument stands for one type of value the internal computation can handle. Templates (instead of function overloading) are needed because the values are passed as boost::any and their types are not clear before runtime.
To properly cast to the correct types, I would like to have a member list for each variadic argument type, something like this:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::vector<T1> m_argumentsOfType1;
std::vector<T2> m_argumentsOfType2; // ...
};
Or alternatively, I'd like to store the template argument types in a list, as to do some RTTI magic with it (?). But how to save them in a std::initializer_list member is also unclear to me.
Thanks for any help!
As you have already been hinted, the best way is to use a tuple:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::tuple<std::vector<AcceptedTypes>...> vectors;
};
This is the only way to multiply the "fields" because you cannot magically make it spell up the field names. Another important thing may be to get some named access to them. I guess that what you're trying to achieve is to have multiple vectors with unique types, so you can have the following facility to "search" for the correct vector by its value type:
template <class T1, class T2>
struct SameType
{
static const bool value = false;
};
template<class T>
struct SameType<T, T>
{
static const bool value = true;
};
template <typename... Types>
class MyClass
{
public:
typedef std::tuple<vector<Types>...> vtype;
vtype vectors;
template<int N, typename T>
struct VectorOfType: SameType<T,
typename std::tuple_element<N, vtype>::type::value_type>
{ };
template <int N, class T, class Tuple,
bool Match = false> // this =false is only for clarity
struct MatchingField
{
static vector<T>& get(Tuple& tp)
{
// The "non-matching" version
return MatchingField<N+1, T, Tuple,
VectorOfType<N+1, T>::value>::get(tp);
}
};
template <int N, class T, class Tuple>
struct MatchingField<N, T, Tuple, true>
{
static vector<T>& get(Tuple& tp)
{
return std::get<N>(tp);
}
};
template <typename T>
vector<T>& access()
{
return MatchingField<0, T, vtype,
VectorOfType<0, T>::value>::get(vectors);
}
};
Here is the testcase so you can try it out:
int main( int argc, char** argv )
{
int twelf = 12.5;
typedef reference_wrapper<int> rint;
MyClass<float, rint> mc;
vector<rint>& i = mc.access<rint>();
i.push_back(twelf);
mc.access<float>().push_back(10.5);
cout << "Test:\n";
cout << "floats: " << mc.access<float>()[0] << endl;
cout << "ints: " << mc.access<rint>()[0] << endl;
//mc.access<double>();
return 0;
}
If you use any type that is not in the list of types you passed to specialize MyClass (see this commented-out access for double), you'll get a compile error, not too readable, but gcc at least points the correct place that has caused the problem and at least such an error message suggests the correct cause of the problem - here, for example, if you tried to do mc.access<double>():
error: ‘value’ is not a member of ‘MyClass<float, int>::VectorOfType<2, double>’
An alternate solution that doesn't use tuples is to use CRTP to create a class hierarchy where each base class is a specialization for one of the types:
#include <iostream>
#include <string>
template<class L, class... R> class My_class;
template<class L>
class My_class<L>
{
public:
protected:
L get()
{
return val;
}
void set(const L new_val)
{
val = new_val;
}
private:
L val;
};
template<class L, class... R>
class My_class : public My_class<L>, public My_class<R...>
{
public:
template<class T>
T Get()
{
return this->My_class<T>::get();
}
template<class T>
void Set(const T new_val)
{
this->My_class<T>::set(new_val);
}
};
int main(int, char**)
{
My_class<int, double, std::string> c;
c.Set<int>(4);
c.Set<double>(12.5);
c.Set<std::string>("Hello World");
std::cout << "int: " << c.Get<int>() << "\n";
std::cout << "double: " << c.Get<double>() << "\n";
std::cout << "string: " << c.Get<std::string>() << std::endl;
return 0;
}
One way to do such a thing, as mentioned in πάντα-ῥεῖ's comment is to use a tuple. What he didn't explain (probably to save you from yourself) is how that might look.
Here is an example:
using namespace std;
// define the abomination
template<typename...Types>
struct thing
{
thing(std::vector<Types>... args)
: _x { std::move(args)... }
{}
void print()
{
do_print_vectors(std::index_sequence_for<Types...>());
}
private:
template<std::size_t... Is>
void do_print_vectors(std::index_sequence<Is...>)
{
using swallow = int[];
(void)swallow{0, (print_one(std::get<Is>(_x)), 0)...};
}
template<class Vector>
void print_one(const Vector& v)
{
copy(begin(v), end(v), ostream_iterator<typename Vector::value_type>(cout, ","));
cout << endl;
}
private:
tuple<std::vector<Types>...> _x;
};
// test it
BOOST_AUTO_TEST_CASE(play_tuples)
{
thing<int, double, string> t {
{ 1, 2, 3, },
{ 1.1, 2.2, 3.3 },
{ "one"s, "two"s, "three"s }
};
t.print();
}
expected output:
1,2,3,
1.1,2.2,3.3,
one,two,three,
There is a proposal to allow this kind of expansion, with the intuitive syntax: P1858R1 Generalized pack declaration and usage. You can also initialize the members and access them by index. You can even support structured bindings by writing using... tuple_element = /*...*/:
template <typename... Ts>
class MyClass {
std::vector<Ts>... elems;
public:
using... tuple_element = std::vector<Ts>;
MyClass() = default;
explicit MyClass(std::vector<Ts>... args) noexcept
: elems(std::move(args))...
{
}
template <std::size_t I>
requires I < sizeof...(Ts)
auto& get() noexcept
{
return elems...[I];
}
template <std::size_t I>
requires I < sizeof...(Ts)
const auto& get() const
{
return elems...[I];
}
// ...
};
Then the class can be used like this:
using Vecs = MyClass<int, double>;
Vecs vecs{};
vecs.[0].resize(3, 42);
std::array<double, 4> arr{1.0, 2.0, 4.0, 8.0};
vecs.[1] = {arr.[:]};
// print the elements
// note the use of vecs.[:] and Vecs::[:]
(std::copy(vecs.[:].begin(), vecs.[:].end(),
std::ostream_iterator<Vecs::[:]>{std::cout, ' '},
std::cout << '\n'), ...);
Here is a less than perfectly efficient implementation using boost::variant:
template<typename ... Ts>
using variant_vector = boost::variant< std::vector<Ts>... >;
template<typename ...Ts>
struct MyClass {
using var_vec = variant_vector<Ts...>;
std::array<var_vec, sizeof...(Ts)> vecs;
};
we create a variant-vector that can hold one of a list of types in it. You have to use boost::variant to get at the contents (which means knowing the type of the contents, or writing a visitor).
We then store an array of these variant vectors, one per type.
Now, if your class only ever holds one type of data, you can do away with the array, and just have one member of type var_vec.
I cannot see why you'd want one vector of each type. I could see wanting a vector where each element is one of any type. That would be a vector<variant<Ts...>>, as opposed to the above variant<vector<Ts>...>.
variant<Ts...> is the boost union-with-type. any is the boost smart-void*. optional is the boost there-or-not.
template<class...Ts>
boost::optional<boost::variant<Ts...>> to_variant( boost::any );
may be a useful function, that takes an any and tries to convert it to any of the Ts... types in the variant, and returns it if it succeeds (and returns an empty optional if not).
I'm using the following compile-time 'trick' (based on ADL) to create a function that is only valid/defined/callable by classes in the same namespace.
namespace Family1
{
struct ModelA{};
struct ModelB{};
template<typename T>
bool is_in_Family1(T const& t)
{
return true;
}
};
namespace Family2
{
struct ModelC{};
template<typename T>
bool is_in_Family2(T const& t)
{
return true;
}
};
Family1::ModelA mA;
Family2::ModelC mC;
is_in_Family1(mA); // VALID
is_in_Family1(mC); // ERROR
Now, I'd like to use this principle (or something similar) in order to produce a specialization of Foo::Bar (below) for classes belonging to each of the namespaces e.g. Family1.
// I would like to specialize the method template Bar for classes in Family1
// namespace; and another specialization for classes in Family2 namespace
struct Foo
{
template<typename T>
void Bar( T& _T ){}
};
For ease of maintenance and the large number of classes in each namespace, if possible, I'd like to perform this check without naming all the classes in a namespace.
Your "trick" has one big problem. Try calling is_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC()) and you will see that return true, because ADL will look into both the namespaces of ModelA and ModelC (because of pair<ModelA, ModelC>).
Ignoring that problem, with using your functions it is straight forward.
template<typename T> struct int_ { typedef int type; };
struct Foo
{
template<typename T,
typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
>
void Bar( T& t ){}
template<typename T,
typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
>
void Bar( T& t ){}
};
That calls Bar depending on whether it is in family2 or family1.
struct Foo
{
template<typename T,
typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
>
void Bar( T& t, long){}
template<typename T,
typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
>
void Bar( T& t, long){}
template<typename T>
void Bar( T& t, int) {}
template<typename T>
void Bar( T& t ) { return Bar(t, 0); }
};
That one has also a generic fallback. And your code had undefined behavior because you used a reserved name. Don't use _T.
The quickest way I found to do this is using Boost Type Traits' is_base_of<>
I tried to use inheritence with template specialization but that didn't work because inheritance is ignored when template specialization is used so you'd have to specialize for each model. The answer to Partial specialization for a parent of multiple classes explains the problem.
Using type traits works provided you make Family1::ModelA and Family::ModelB subclasses of Family1:Family1Type and Family2::ModelC a subclass of Family2::Family2Type :
#include <iostream>
#include <boost/type_traits/is_base_of.hpp>
namespace Family1{
struct Family1Type{};
struct ModelA :public Family1Type{};
struct ModelB :public Family1Type{};
template<typename T>
bool is_in_Family1(const T& t){
return boost::is_base_of<Family1::Family1Type,T>::value;
}
};
namespace Family2{
struct Family2Type{};
struct ModelC :public Family2Type{};
template<typename T>
bool is_in_Family2(const T& t){
return boost::is_base_of<Family2::Family2Type,T>::value;
}
};
using namespace std;
int main(int argc, char *argv[]) {
Family1::ModelA mA;
Family2::ModelC mC;
std::cout << "mA is in Family1? " << is_in_Family1(mA) << std::endl;
std::cout << "mC is in Family2? " << is_in_Family2(mC) << std::endl;
//std::cout << "mC is in Family1? " << is_in_Family1(mC) << std::endl; //ERROR!
//std::cout << "mA is in Family2? " << is_in_Family2(mA) << std::endl; //ERROR!
return 0;
}
This results in the following output:
mA is in Family1? 1
mC is in Family2? 1
I don't think there is a way to declare Foo and specialize Foo::Bar<> in another namespace according to Specialization of 'template<class _Tp> struct std::less' in different namespace