1

How does one specialize a template function to generate an error at compile-time if a user attempts to call said function with a given template parameter?

I was able to get this behavior for a template class by using the following idiom...

template <typename T>
class MyClass< std::vector<T> >;

The basic signature of the function which I am trying to modify is...

template <typename T>
T bar(const int arg) const {
  ...
}

If I use the same paradigm that I used to disallow certain template classes...

template<>
std::string foo::bar(const int arg) const;

I can generate a linker error, which I suppose is more desirable than a runtime error, but still not really what I'm looking for.

Since I am not able to use C++11, I cannot use static_assert, as described here. Instead, I am trying to use BOOST_STATIC_ASSERT like so...

template<>
std::string foo::bar(const int arg) const {
  BOOST_STATIC_ASSERT(false);
  return "";
}

However, this generates the following compile-time error, even when I am not trying to call an instance of the function with the template parameter I am attempting to disallow...

error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'

I found this post, but it doesn't really offer any insight that I feel applies to me. Can anyone help?

Community
  • 1
  • 1
Dan Forbes
  • 2,734
  • 3
  • 30
  • 60

2 Answers2

5

Use boost::is_same to generate a compile-time boolean value that can then be used with BOOST_STATIC_ASSERT to perform the check.

template <typename T>
T bar(const int) 
{
  BOOST_STATIC_ASSERT_MSG((!boost::is_same<T, std::string>::value), 
                          "T cannot be std::string");
  return T();
}

bar<int>(10);
bar<std::string>(10);  // fails static assertion

Live demo

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • This throws an (unwanted) compile-time error... `BOOST_STATIC_ASSERT(!boost::is_same::value, "my message");` produces `error: macro "BOOST_STATIC_ASSERT" passed 3 arguments, but takes just 1` and `error: 'BOOST_STATIC_ASSERT' was not declared in this scope`. Note that I called `BOOST_STATIC_ASSERT(true)` without issue. – Dan Forbes Jun 16 '14 at 16:42
  • 4
    @DanForbes Notice the extra set of parentheses in my example? :) Without those the comma in `is_same` is interpreted as an argument separator by the preprocessor. Also, you need `BOOST_STATIC_ASSERT_MSG` is you want to add a message. – Praetorian Jun 16 '14 at 16:45
  • Derp. Accepting this answer as it is simple and provides the exact behavior I am looking for. – Dan Forbes Jun 16 '14 at 17:04
2

It seems C++ don't allow specialize template member function. So if you want to use same interface, you should use other technology. I'd like to use trait_type to implement this.

template <class T>
struct is_string : false_type {};
template <>
struct is_string<string> : true_type {};

template <typename T>
class MyClass {
 private:
  T bar(const int arg, false_type) const {
    return T();
  }

  std::string bar(const int arg, true_type) const {
    return "123";
  }
 public:
  T bar(const int arg) const {
    return bar(arg, is_string<T>());
  }
};

If you can not use C++11, you must implement false_type and true_type yourself. Or you can use specialize template class.

ronaflx
  • 53
  • 5
  • Although I appreciate your answer, and it may work, the answer provided by @Praetorian above is much simpler and provides the exact behavior I am looking for. – Dan Forbes Jun 16 '14 at 17:05
  • I'm pretty sure `std::true_type` and `std::false_type` were in C++03 weren't they? Or at least in TR1? – Mooing Duck Jun 16 '14 at 17:13
  • @MooingDuck Only in TR1. – Constructor Jun 16 '14 at 18:15
  • C++ allows to (fully) specialize a template member function. But the question isn't about it. Your code compiles successfully even with `std::string` passed as a template parameter. – Constructor Jun 16 '14 at 18:18