Bulletmagnet
Bulletmagnet

Reputation: 6022

BOOST_STRONG_TYPEDEF almost, but not quite, like its base

I want this templated code to work on std::string, a BOOST_STRONG_TYPEDEF of std::string, and std::vector.

#include <boost/strong_typedef.hpp>
#include <string>
#include <vector>
#include <iostream>
BOOST_STRONG_TYPEDEF(std::string, number_value)

template <typename T>
void say(T const& v)
{
    if (v.empty()) { // doesn't work for number_value
        return; // cool, nothing to do!
    }
    if (static_cast<std::string>(v).empty()) { // doesn't work for vector
        return; // cool, nothing to do!
    }

    std::cout << v.size() << "\n";
}

int main()
{
    std::string s;
    number_value n;
    std::vector<std::string> strings;

    say(s);
    say(n);
    say(strings);
}

BOOST_STRONG_TYPEDEF(T,D) is mostly

struct D {
    T t;
};

and a bunch of constructors, conversion and comparison operators to make D look like a T.

Unfortunately, I can't find a way to transparently access methods of std::string on number_value, the almost, but not quite, entirely unlike std::string type.

I tried to hide the call to size behind some intermediate functions:

template <typename T>
size_t get_size(T const& v)
{
    return v.size();
}

template <typename T>
typename std::enable_if<std::is_convertible<T, std::string>::value, size_t>::type get_size(T const& v)
{
    return static_cast<std::string>(v).size();
}

but my metaprogramming-fu is not strong enough (get_size is ambiguous for number_value).

Any suggestions?

Upvotes: 1

Views: 345

Answers (2)

Drax
Drax

Reputation: 13288

You just need to disable the generic template when your specialisation matches:

#include <boost/strong_typedef.hpp>
#include <string>
#include <vector>
#include <iostream>

template <typename T>
typename std::enable_if<!std::is_convertible<T, std::string>::value, std::size_t>::type get_size(T const& v)
{
  return v.size();
}

template <typename T>
typename std::enable_if<std::is_convertible<T, std::string>::value, std::size_t>::type get_size(T const& v)
{
  return static_cast<std::string>(v).size();
}

template <typename T>
bool    is_empty(const T& v)
{
  return (get_size(v) == 0);
}

BOOST_STRONG_TYPEDEF(std::string, number_value)

template <typename T>
void say(T const& v)
{
  if (is_empty(v)) {
    return; // cool, nothing to do!
  }

  std::cout << get_size(v) << "\n";
}

int main()
{
  std::string s;
  number_value n;
  std::vector<std::string> strings;

  say(s);
  say(n);
  say(strings);
}

Upvotes: 1

dewaffled
dewaffled

Reputation: 2973

The simple way is to add explicit specialization of function template for strong-typedefed type and just use implementation for underlying value:

template <>
void say(number_value const& v)
{
    say(static_cast<std::string>(v));
}

Upvotes: 0

Related Questions