Lingxi
Lingxi

Reputation: 14977

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.

Upvotes: 4

Views: 5313

Answers (3)

davidhigh
davidhigh

Reputation: 15488

As a shorter version of @5gon12eder's good answer, you can simply use

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

Upvotes: 0

5gon12eder
5gon12eder

Reputation: 25419

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.)

Upvotes: 9

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");

Upvotes: 4

Related Questions