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

Is it possible to check if the function has a void return type

本文关键字:是否 void 返回类型 函数 检查      更新时间:2023-10-16

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

我需要做一个编译时检查当前函数是否具有void返回类型,如果返回类型为 void,则编译失败。

我试图用 http://en.cppreference.com/w/cpp/types/result_of 和decltype做一些魔法,但我就是无法更接近解决方案。

#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() {
}

那么问题来了:

是否可以为当前函数执行此操作?

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

如果

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

这段代码编译得很好:

constexpr bool startsWith(const char* a, const char* b) {
    return *a == *b && (*(a + 1) == '' || startsWith(a + 1, b + 1));
}
int f() {
    static_assert(!startsWith("void ", __PRETTY_FUNCTION__), "not void");
    return 1;
}

int main() {
}

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

constexpr bool startsWith(const char* a, const char* b) {
    return *a == *b && (*(a + 1) == '' || 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__ ...使其在各种编译器之间更具可移植性,但我相信这是另一个问题的主题。

如果你可以命名当前函数,那么最简单的方法是:

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

试试这个:

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 {}; }

只要使用前六个函数调用return_void,所有对 的调用都将返回 true,return_void(l)return_void(m) 调用将返回 false,因为它们将调用模板的第二个版本,即返回 false 的版本。

在线查看

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

int main() {
    static_assert(return_void(f), "not void");
    if (!return_void(m))
        std::cout << "m result is: " << m(0) << 'n';
    return 0;
}

可以通过检查死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有点复杂,但仍然可行。

您所需要的只是检测返回类型并检查它是否为 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);
}