提问人:Arty 提问时间:12/30/2020 更新时间:12/30/2020 访问量:733
如何在 C++ 中检查标识符是否已声明?
How to check in C++ that identifier is declared?
问:
我想在代码的某个点检查是否声明了某个标识符,我该怎么做?x
我需要对不同类型的标识符进行这种检查 - 变量、枚举常量、函数、类型、宏等。但首先,我至少要检查变量和函数。
我需要这种检查(例如虚构),以便下一个代码可以工作,例如对于 int 变量的情况:declared(x)
x
if constexpr(declared(x)) {
int y = x + 1;
} else {
std::cout << "Variable 'x' not declared!" << std::endl;
}
对于原因宏的情况,我可以使用,但是如何对变量/函数进行相同的检查?#ifdef x
对于全局非 lambda 函数的情况,我根据重载函数解析找出了下一个代码,但它需要使用基于辅助宏的全局定义(可以更简化吗?
#include <iostream>
#include <type_traits>
#define declared_func_helper(x, ...) \
struct NotDeclared; \
template <typename ... Args> \
NotDeclared x(Args ...); \
template <typename ... Args> \
inline constexpr bool declared_func_##x(Args && ... args) { \
return !std::is_same_v<decltype(x(args...)), NotDeclared>; \
}
// declare some of functions
//void f(int a) {}
void g(bool b, char c) {}
// define helpers before or after declared functions
declared_func_helper(f);
declared_func_helper(g);
int main() {
// check declaration of functions
std::cout << "func 'f' declared: " << std::boolalpha << declared_func_f(int()) << std::endl;
std::cout << "func 'g' declared: " << std::boolalpha << declared_func_g(bool(), char()) << std::endl;
}
输出:
func 'f' declared: false
func 'g' declared: true
对于非全局变量的情况,我实现了下一个代码,但它也需要通过宏定义帮助程序:
#include <type_traits>
#include <iostream>
#define declared_var_helper(x) \
struct NotDeclared_##x {}; \
NotDeclared_##x x;
#define declared_var(x) \
([&](){ return !std::is_same_v<decltype(x), NotDeclared_##x>; }())
// use helpers before variables declaration
declared_var_helper(x);
declared_var_helper(y);
int main() {
// declare some of variables
//bool x = false;
int y = 0;
// ........
// later check declaration
constexpr bool is_declared_x = declared_var(x), is_declared_y = declared_var(y);
std::cout << std::boolalpha << "var 'x' declared: " << is_declared_x << std::endl;
std::cout << "var 'y' declared: " << is_declared_y << std::endl;
}
输出:
var 'x' declared: false
var 'y' declared: true
其他情况或更简单的检查方法呢?
答:
0赞
SparkyPotato
12/30/2020
#1
对于函数问题,您可以做的是声明一个全局函数指针,您的客户端必须填写该指针,并且默认情况下设置为您的函数。
例如:
const auto Function = Function_Fallback
然后到处使用。Function
评论
0赞
Arty
12/30/2020
您有一个运行时解决方案。原因,这是可能的。在运行时,你可以做任何复杂的事情。但我想要编译时解决方案。为什么?例如,我有一个非常高性能的代码部分,在该代码中,我总是只想编译一个分支 - 无论是用于定义的客户端函数还是用于回退。我负担不起额外的运行时布尔条件检查。另一个更重要的问题是,有时这些定义的函数可能是几十个或数百个不同的函数。而且这些函数可能在第三方库中,我不希望我的客户端做额外的初始化指针工作
0赞
SparkyPotato
12/30/2020
没有运行时布尔值检查。您只是使用函数指针,它与调用普通函数具有相同的开销。
0赞
Arty
12/30/2020
通过运行时解决方案,我实际上意味着我必须通过指针使用函数。想象一下,实际函数是在客户端标头中定义的一些短函数。如果我的代码直接使用此内联函数,则任何编译器都将在我的代码中内联并优化此函数调用。但是,如果指针使用函数,那么首先它不会被内联,其次将没有机会在发布时进行优化。我需要对我的高性能代码进行内联优化。inline
0赞
Arty
12/30/2020
第二件更重要的事情是,可以有数十个/数百个这样的不同函数,并且可以在第三方库中定义它们。使用额外的指针解决方案,所有客户端都必须初始化所有数百个函数的指针,即做大量的编码工作,而不仅仅是包括第三方库和编译我的代码。
0赞
utnapistim
12/30/2020
#2
这扩展了@500-internal-server-error的评论。
从您的评论中,我了解到您正在尝试将自定义点添加到您的库中。
在 OOP 中执行此操作的规范方法是为您要执行的操作定义接口(基类),并为它们添加默认实现。
然后,指定(通过文档和示例)代码的用户如何自定义此行为以满足其需求。
为此,您不需要检查客户端是否/在其代码中声明了什么。
下面是一个示例(使用一些假设类来序列化数据):
class Document // your data class, that you needd to save
{
int a = 0; // document data (that needs to be saved)
int b = 1;
public:
void save() // by default, save to xml
{
XmlDocument store{"document.xml"};
save(store);
}
void save(OutputDocument &store)
{
store.add("a", to_string(a));
store.add("b", to_string(b));
}
};
自定义点 (OutputDocument):
class OutputDocument
{
public:
virtual void add(const std::string& name, const std::string& value) = 0;
};
默认实现 (XML):
class XmlDocument: public OutputDocument
{
public:
void add(const std::string& name, const std::string& value) override;
};
自定义(客户端可以执行此操作):
class JsonDocument: public OutputDocument // store to JSON instead
{
public:
void add(const std::string& name, const std::string& value) override;
};
客户可以说:
Document doc;
JsonDocument json{"document.json"};
doc.save(json); // save to json instead of the default (to xml)
评论
0赞
Arty
12/30/2020
为什么我不能使用接口?在这里看到我的评论。原因之一是我负担不起高性能代码中的额外虚拟级别。其次,更重要的是,数百个这样的函数可能来自某个第三方库,其中一些函数是由宏有条件定义的。我不希望我的客户端费心通过额外的虚拟接口转发所有这些数百个函数。我想直接使用第三方库函数。#ifdef ...
评论
x
x
if constexpr(declared(x)) { ... }