Question

I have a template function. It has well defined semantics so long as the argument is not a pointer type. If someone calls this function passing an argument of type pointer I want to force a compile time error. I have no trouble writing the general (legal) template and the corresponding partially specialized (illegal) version. I just cannot figure out how to defer an error from function definition to function invocation.

Was it helpful?

Solution

You don't need to specialize it, actually. Just add this in your function body:

BOOST_STATIC_ASSERT(!boost::is_pointer<T>()::value);

This will cause a failure which should be fairly easy to understand.

OTHER TIPS

Using C++0x: (see it live on http://ideone.com/ZMNb1)

#include <type_traits>
#include <iostream>

template <typename T>
    void cannot_take_pointer(T ptr)
{
    static_assert(!std::is_pointer<T>::value, 
        "cannot_take_pointer requires non-pointer argument");
    std::cout << "ok\n";
}

int main()
{
    int x;
    cannot_take_pointer(x);
    cannot_take_pointer(&x);  // fails to compile
}

sounds like a perfect case for boost::disable_if. Something like this should work.

template <class T>
void func(T x, typename boost::disable_if<boost::is_pointer<T> >::type* dummy = 0) {
    std::cout << x << std::endl;
}


func(10); // works
func(std::string("hello")); // works
func("hello world"); // error: no matching function for call to 'func(const char [6])'
func(new int(10)); // error: no matching function for call to 'func(int*&)'

If you want to do this on your own (instead of using something like BOOST_STATIC _ASSERT), there are two or three basic tricks that are usually involved.

The first (and probably most important, in your case) is to use sizeof (with the result cast to void, usually) to get some code compiled without producing anything that will execute at compile time.

The second is to produce some code that's illegal under the right circumstances. One typical method is to create an array that will have a size equal to the value of some expression. If the expression has a value of 0, the array will have 0 size, which isn't allowed. Alternatively, if the size is one, it will be legal. The one problem with that is is the error message it produces is usually pretty meaningless -- it's hard to guess how "error: array must have positive size" (or something like that) relates to "the template parameter must not be a pointer".

To produce a more meaningful error message, you usually use a slightly different trick. In this case, a conversion from one class to another, that will fail if an expression is false, but succeed if it's true. One way to do that is like this:

template <bool>
struct check {  check(...);  };

template <>
class check<false> {};

The check(...); means any other type can (theoretically) be converted to a check<true> (but note that we only declare the function, never define it, so if you tried to execute such code, it wouldn't link). The lack of any conversion constructor in check<false> means attempting to convert anything else to a check<false> will always fail.

We can then use that with a macro something like this:

#define STATIC_ASSERT(expr, msg) {       \
    struct Error_##msg {};               \
    (void)sizeof(check<(expr)!=0>((Error_##msg))); \
}

You'd use this something like: STATIC_ASSERT(whatever, parameter_cannot_be_a_pointer);. That would expand to something like:

struct Error_parameter_cannot_be_a_pointer {};
(void)sizeof(check<(expr)!=0>(Error_parameter_cannot_be_a_pointer);

Then, if expr != 0, it'll attempt to convert Error_parameter_cannot_be_a_pointer to a check<true>, which will succeed.

On the other hand, if expr does equal 0, it'll attempt to convert to a check<false>, which will fail. We at least hope that when that happens, we get an error message something like this:

 error cannot convert:
     Error_parameter_cannot_be_a_pointer
 to
     check<false>

Obviously we'd like an even better message than that if we could, but even as it stands, that's not too terrible. You just have to ignore the "wrapping", and look at the name of the source type to get a pretty good idea of the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top