Sending tags against static methods on partially specialized classes

Suppose I want to write a generic function void f<T>() that does one if T is a POD type and the other thing if T is a non-POD (or any other arbitrary predicate).

One way to achieve this is to use a tag submission template, such as a standard library, with iterator categories:

 template <bool> struct podness {}; typedef podness<true> pod_tag; typedef podness<false> non_pod_tag; template <typename T> void f2(T, pod_tag) { /* POD */ } template <typename T> void f2(T, non_pod_tag) { /* non-POD */ } template <typename T> void f(T x) { // Dispatch to f2 based on tag. f2(x, podness<std::is_pod<T>::value>()); } 

An alternative would be to use a static member function of partially specialized types:

 template <typename T, bool> struct f2; template <typename T> struct f2<T, true> { static void f(T) { /* POD */ } }; template <typename T> struct f2<T, false> { static void f(T) { /* non-POD */ } }; template <typename T> void f(T x) { // Select the correct partially specialised type. f2<T, std::is_pod<T>::value>::f(x); } 

What are the pros and cons of using one method over another? What would you recommend?

+44
c ++ generic-programming metaprogramming partial-specialization
Aug 02 '11 at 18:53
source share
4 answers

I want to send the tag because:

  • Easy to spread with new tags
  • Easy to use inheritance ( example )
  • This is a fairly common technique in general programming.

It seems to me difficult to add the third option in the second example. When you want to add, for example, non-POD-of-PODs, you will have to replace bool with template <typename T, bool> struct f2; with something else ( int if you like =)) and replace all struct f2<T, bool-value> with struct f2<T, another-type-value> . So for me the second option looks barely extensible. Please correct me if I am wrong.

+15
Aug 03 '11 at 1:00 p.m.
source share

A readable alternative to [boost|std]::enable_if , tags and partial specialization for easy sending compilation that I like are as follows:

[Remember that booleans have a conversion to integers, that arrays of zero length are invalid and that violation patterns are discarded (SFINAE). In addition, char (*)[n] is a pointer to an array of n elements.]

 template <typename T> void foo(T, char (*)[is_pod<T>::value] = 0) { // POD } template <typename T> void foo(T, char (*)[!is_pod<T>::value] = 0) { // Non POD } 

It also has the advantage of not needing external classes that pollute the namespace. Now, if you want to externalize the predicate, as in your question, you can do:

 template <bool what, typename T> void foo(T, char (*)[what] = 0) { // taken when what is true } template <bool what, typename T> void foo(T, char (*)[!what] = 0) { // taken when what is false } 

Using:

 foo<std::is_pod<T>::value>(some_variable); 
+15
Aug 2 '11 at 19:17
source share

In fact, both have only a tag sending template. The former is called an instance dispatch tag, and the latter is called a type dispatch tag.

Barend, the main author of Boost.Geometry, explains both methods and prefers the latter. This is widely used in Boost.Geometry. The following are the benefits:

  • There is no need to create a tag instance, since its sole purpose is to distinguish between
  • Easily Define New Types and Constants Based on Tags
  • Arguments can be canceled in the interface, i.e. distance(point, polygon); and distance(polygon, point); can have only one implementation
+9
07 Oct '13 at 10:15
source share

I know this is an old question with an already accepted answer, but this could be a viable alternative:

 template<typename T> std::enable_if_t<std::is_pod<T>::value> f(T pod) { } template<typename T> std::enable_if_t<!std::is_pod<T>::value> f(T non_pod) { } 
+1
Oct 21 '15 at 19:35
source share



All Articles