Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forbids functions with `static_assert`

I want to prevent certain functions from being called. Let's ignore the case of calling the function via a function pointer or something, and just concentrate on the case of direct function call. I can do this with = delete. However, the diagnostic issued is not quite informative. I considered using static_assert, with which you can supply a custom diagnostic message. I placed a static_assert(false, ...) statement within the function body, hoping that it fires when the function is called. However, it turns out that the static_assert fails even if the function is not called. Any suggestions?

Additional Note: The function is forbidden unconditionally. So, std::enable_if does not apply here. The motivation for such a function is that I want to prevent certain use, which would otherwise compile fine with overload resolution. So I can't just remove the function. deprecated is not what I want. I want a compilation error, not a warning.

like image 550
Lingxi Avatar asked Dec 19 '22 20:12

Lingxi


2 Answers

I agree with others that you shouldn't use static_assert for this at all and mark the function as deprecated instead.

static_assertions fire at the time they are compiled. For an ordinary function, this is the time it is parsed, not the time it is called. For a template, however, it is the time of instantiation. So you can make your function a template like this.

template <typename...>
struct always_false { static constexpr bool value = false; };

template <typename... Ts>
void
never_call_me(Ts&&...)
{
  static_assert(always_false<Ts...>::value,
                "You should have never called this function!");
}

If typename... is not right for you (because the function is overloaded), try narrowing it down to only match what you want to make an error.

The trick used here is that always_false<Ts...>::value depends on the type parameters Ts... so it cannot be evaluated until the template is instantiated. (Even though we can clearly see that it will always be false.)

like image 176
5gon12eder Avatar answered Dec 24 '22 02:12

5gon12eder


If it is a member function then = delete is your best (most portable) bet. Otherwise, both GCC and MSVC have support for marking a function as "deprecated", which will cause the compiler to issue a warning when the function is called.

From C++ mark as deprecated:

#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED(func) func
#endif

Usage:

DEPRECATED(void badidea(int a, const char* b));

.... and now with C++ 14, we can write it as:

#define DEPRECATED(func, reason) [[deprecated(reason)]] func

With usage:

DEPRECATED( void badidea(int a, const char* b), "This function was a bad idea");
like image 20
Martin Bonner supports Monica Avatar answered Dec 24 '22 01:12

Martin Bonner supports Monica