编译时使用内省

时间:2013-12-07 02:42:03

标签: c++

我一直试图找到解决这个问题的方法已经有一段时间了,到目前为止,每个人都告诉我这是不可能的,所以我虽然试试看。

问题出在这里:人们使用环境变量而不是正确地测试结果或者使用硬编码的替代方法。

我想要做的是想出一个人们可以使用的小型库而不是getenv,它可以在初始化时通知用户env。程序可能正在使用的变量。这只会意味着为这个调用替换getenv并在可执行文件或库的初始化时放置一个函数调用(我不会处理动态的env。变量名称制作,例如使用构造的字符串)。

以下是我能够制作的快速示例(http://ideone.com/Wi1JBq

#include <iostream>
#include <vector>

using namespace std;

static vector<string> test;

template <char const *str>
struct EnvVar
{
    EnvVar()
    {
        test.push_back(string(str));
    }
    const char* GetEnvVarName() const
    {
        return str;
    }
};

static void checkVars()
{
    for(unsigned int i = 0; i < test.size(); i++)
        cout << "Predefined : " << test[i] << endl;
}

#define GENERATE_ENV_VAR(Name) char _##Name[] = #Name; static EnvVar<_ ## Name> Name;

// ----- What is actually in the user file -----

GENERATE_ENV_VAR(FirstEnvVar)
GENERATE_ENV_VAR(SecondEnvVar)
GENERATE_ENV_VAR(ThirdEnvVar)

int main()
{
    checkVars();
    cout << "Usage : " << FirstEnvVar.GetEnvVarName() << endl;
    cout << "Usage : " << SecondEnvVar.GetEnvVarName() << endl;
    cout << "Usage : " << ThirdEnvVar.GetEnvVarName() << endl;
    return 0;
}

此输出

Predefined : FirstEnvVar
Predefined : SecondEnvVar
Predefined : ThirdEnvVar
Usage : FirstEnvVar
Usage : SecondEnvVar
Usage : ThirdEnvVar

很明显为什么它这样做,在全局级别使用宏,这是在输入main之前初始化的,这就是第一个函数调用知道它们的原因。我想做的是没有那些,所以基本上,有这个:

int main()
{
    checkVars();
    cout << "Usage : " << FirstEnvVar.GetEnvVarName() << endl;
    cout << "Usage : " << SecondEnvVar.GetEnvVarName() << endl;
    cout << "Usage : " << ThirdEnvVar.GetEnvVarName() << endl;
    return 0;
}

并获得相同的输出。我敢肯定它会涉及很多模板/宏黑客,但它会很棒。我不希望有一个脚本解析代码并生成代码,但我知道这可能是一个解决方案。如果可能,我想要纯C ++,提升可以很好。

谢谢。

1 个答案:

答案 0 :(得分:0)

为什么需要成为模板类?您应该能够将#NAME传递给接受const char *的构造函数。在到达main中的代码之前,运行时将调用所有文件范围变量实例的构造函数。

class EnvVar
{ 
  private:
    const char *const str;

  public:
    static vector<string> env_vars;

    EnvVar(const char *str_) : str(str_)
    {
        env_vars.push_back(string(str_));  // this vector seems redundant...
    }
    const char* GetEnvVarName() const
    {
        return str;
    }
};

#define GENERATE_ENV_VAR(Name)  EnvVar Name##_( #Name );

GENERATE_ENV_VAR(FirstEnvVar)
GENERATE_ENV_VAR(SecondEnvVar)
GENERATE_ENV_VAR(ThirdEnvVar)

您还会注意到我将下划线移动到变量名称的末尾,因为前导下划线后跟大写字母保留给编译器。

此外,vector<string>似乎是多余的。实际上,有一个EnvVar指针的中央注册表可以更有意义,类注册自己,如下所示:

class EnvVar
{ 
  private:
    const char *const str;

  public:
    static vector<class EnvVar *> registry;

    EnvVar(const char *str_) : str(str_)
    {
        registry.push_back(this);  // register ourselves
    }
    const char* GetEnvVarName() const
    {
        return str;
    }
};

然后,您可以通过迭代EnvVars::registry来完成环境变量的完整注册表。