是否可以检查函数是否具有void返回类型

时间:2016-07-07 11:19:09

标签: c++ c++11

这个非常奇怪的要求出现了......

我需要进行编译时检查当前函数是否具有void返回类型,如果返回类型为void则无法编译。

我也尝试用http://en.cppreference.com/w/cpp/types/result_ofdecltype做一些魔术,但是我无法接近解决方案。

#include <type_traits>

void other_func(void) { }

void test_maxi(void)
{
    typedef decltype(&::other_func) TYPE;
    static_assert(std::is_same<TYPE, void>::value, "not void"); 
}

int main() {
}

所以问题出现了:

是否可以为当前功能执行此操作?

编辑返回类型检查应该放在宏中,因为它将在多个函数中使用。

5 个答案:

答案 0 :(得分:14)

如果一个字符串文字以另一个字符串开头,则可以实现编译时检查,并使用__PRETTY_FUNCTION__宏,该宏设置为以函数返回类型开头的字符串文字。您应该检查此宏是否以void开头,后跟空格。

此代码编译良好:

constexpr bool startsWith(const char* a, const char* b) {
    return *a == *b && (*(a + 1) == '\0' || startsWith(a + 1, b + 1));
}

int f() {
    static_assert(!startsWith("void ", __PRETTY_FUNCTION__), "not void");
    return 1;
}


int main() {
}

如果您将f返回类型更改为void

constexpr bool startsWith(const char* a, const char* b) {
    return *a == *b && (*(a + 1) == '\0' || startsWith(a + 1, b + 1));
}

void f() {
    static_assert(!startsWith("void ", __PRETTY_FUNCTION__), "not void");
}


int main() {
}

static_assert会开火。

__PRETTY_FUNCTION__宏似乎特定于GNU C ++编译器,但clang++工作正常,因为它也定义了这个宏。如果您正在使用其他编译器,则应检查此宏是否确实已设置,如果没有,请阅读编译器文档以确定类似 宏,例如__FUNCSIG__

你可以使用#ifdef __PRETTY_FUNCTION__ ...来使各种编译器之间更容易移植,但我相信这是另一个问题的主题。

答案 1 :(得分:4)

如果您可以命名当前功能,那么最简单的方法是:

static_assert(!std::is_same<decltype(test_maxi()), void>::value, "void"); 

答案 2 :(得分:4)

试试这个:

tablediff <your parameters> | findstr /i "^Mismatch ^Src"

我们假设我们有以下功能:

template <typename ... Args>
constexpr bool return_void(void(Args ...)) { return true; }

template <typename R, typename ... Args>
constexpr bool return_void(R(Args ...)) { return false; }

void f() {} void g(int) {} void h(int*,char&) {} void i(float,bool) {} void j(const char *const) {} void k(void()) {} int l() { return {}; } float m(int) { return {}; } 的所有调用都将返回true,只要使用前六个函数调用它,return_voidreturn_void(l)调用将返回false,因为它们将调用第二个版本模板,返回假的。

Check it online

这将允许您在运行时和编译时检查函数是否返回return_void(m)

void

答案 3 :(得分:3)

您可以通过检查死return是否可以编译来检查当前函数的返回类型:

struct ConvertToAnything {
    template <class T>
    operator T() const { assert(!"Don't call me!"); }
};

#define CHECK_NONVOID_RETURN() if(true); else return ConvertToAnything{}

int f() {
    CHECK_NONVOID_RETURN(); // Passes
    return 42;
}

void g() {
    CHECK_NONVOID_RETURN(); // Fails at compile-time
}

void的情况属于特殊情况,所以这就足够了。但您也可以通过重载ConvertToAnything::operator Type() = delete;禁止其他类型。允许void涉及更多,但仍然可行。

答案 4 :(得分:0)

您需要的只是检测返回类型并检查它是否为void类型。要检查类型,您可以使用std::is_void。可以使用以下模板检测返回类型:

#include <type_traits> // for is_void

template<typename R, typename... A>
void test(R (*func)(A...)) {
   static_assert(
       !std::is_void<R>::value, 
       "void return type is not allowed"
   ); 
}

// functions to check:
void a(int, char*) {}
int b(char, float) {return 0;}

int main()
{
    test(a); // < assert triggered here
    test(b);
}