为本地变量名添加前缀的“更好”替代方法?

时间:2018-01-27 16:48:22

标签: c++ namespaces naming-conventions variable-names

在我正在撰写的一堆代码中,我想表明某些变量将以某种方式使用,或者具有某些特征。为了便于讨论,假设变量可以是甜的,咸的,酸的或苦的。

我现在使用的是:

int foo() {
    int salty_x;
    int sour_y;
    do_stuff_with(salty_x,sour_y);
}

我可能还有sour_xsalty_y等。

理想情况下 - 但这不是有效的C ++ - 我本来能写出这样的东西:

int foo() {
    namespace salty { int x; }
    namespace sour { int y; }
    do_stuff_with(salty::x,sour::y);
}

这样可以很好地在同一个函数中允许“酸x”和“咸x” - 如果这种语法当然有效。

这可能会提醒你Hungarian Notation,除了它不是关于变量类型或大小,并且咸味或酸味等不是x或y中固有的 - 它们只描述它们的使用方式

现在,您可以问:“好吧,为什么不把这些放在struct中?”,也就是说,为什么不这样做:

int foo() {
    struct { int x; } salty;
    struct { int y; } sour;
    do_stuff_with(salty.x,sour.y);
}

但是那些预先定义了额外的咸/酸变量;如果我把它们全部集中在函数的开头,C风格,那么看起来好像我指出变量是相关的,这不一定是这种情况。

我目前所做的只是在名称前加salty_xsour_y。这很丑,但它确实有效。

我的问题:我还能做些什么,在使用中看起来更接近我想要的代码,同时又不需要太多的“编码体操”?

由于受欢迎的需求:作为激励/具体化的例子,“咸”可能意味着“GPU扭曲中的所有线程都是统一的,但可能不会跨越不同的扭曲”和“酸”可能意味着“在所有线程中均匀”在CUDA内核网格块/ OpenCL工作组中,当它们到达代码中的这一点时“。但这不是关于GPU,CUDA或OpenCL的问题。

4 个答案:

答案 0 :(得分:1)

最难的约束是

  

有时我甚至想要一个"酸x"和一个咸的x"在相同的   功能

所以 - 解决方案是我曾经做过的可变参数模板模板参数的第一次使用 - 所以,你在这里:

template <typename T>
struct salty
{
    T salty;
};
template <typename T>
struct sour
{
    T sour;
};

template <typename T, template <typename> class  ...D>
struct variable : D<T>...
{};

用法:

salty<int> x;
x.salty = 5;

variable<int, salty, sour> y;
y.sour = 6;
y.salty = 5;

答案 1 :(得分:1)

我确定你已经检查过所有传统方法而且都不令人满意......让我们转向魔术然后实现(我认为)你想要的东西(需要c ++ 17) :

#include <iostream>
#include <type_traits>
#include <variant>
#include <utility>
#include <typeinfo>
#include <typeindex>
#include <map>

template <auto Label>
using ic = std::integral_constant<decltype(Label), Label>;

template <class... Ts>
struct context {
    template <auto Label, auto (*Namespace)(std::integral_constant<decltype(Label), Label>)>
    decltype(Namespace(ic<Label>{}))& get() {
        try {
            return std::get<decltype(Namespace(std::integral_constant<decltype(Label), Label>{}))>(values[typeid(std::pair<std::integral_constant<decltype(Namespace), Namespace>, std::integral_constant<decltype(Label), Label>>)]);
        } catch (std::bad_variant_access&) {
            values[typeid(std::pair<std::integral_constant<decltype(Namespace), Namespace>, std::integral_constant<decltype(Label), Label>>)] = decltype(Namespace(std::integral_constant<decltype(Label), Label>{})){};
        }
        return std::get<decltype(Namespace(std::integral_constant<decltype(Label), Label>{}))>(values[typeid(std::pair<std::integral_constant<decltype(Namespace), Namespace>, std::integral_constant<decltype(Label), Label>>)]);
    }
    std::map<std::type_index, std::variant<Ts...>> values;
};

int main(){
    enum { x }; // defining label x
    int salty(ic<x>); // x is an int in salty namespace 
    enum { y }; // defining label y
    float sour(ic<y>); // y is a float in sour namespace
    context<int, float, char> c;


    c.get<x, salty>() = 2;
    c.get<y, sour>() = 3.0f;

    char sour(ic<x>); // x is a char in sour namespace 

    c.get<x, sour>() = 'a';

    std::cout << "salty::x = " << c.get<x, salty>() << std::endl;
    std::cout << "sour::y = " << c.get<y, sour>() << std::endl;
    std::cout << "sour::x = " << c.get<x, sour>() << std::endl;
}

有一件事需要提及 - gcc不喜欢代码,但按照标准应该:[see this] [and that]

答案 2 :(得分:0)

如果我正确理解您的编辑,您希望能够定义与intfloat变量完全相同的变量,但保留有关其类型的其他理想编译时信息。< / p>

我唯一可以帮助你的是:

  

有时我甚至想要一个&#34;酸x&#34;和一个咸的x&#34;在同一个函数中,如果这个语法有效,我可以做。

就个人而言,我只是在变量名前加上前缀。

无论如何,这是你可以做的一个例子。

enum class Flavor {
    Salty, Sour
};

template <typename T, Flavor f>
struct Flavored {
    using Type = T;
    static constexpr Flavor flavor = f;

    T value;

    Flavored(T v) : value(v) {}
    operator T() { return value; }
};

And here is an example of how to use it.

答案 3 :(得分:0)

后缀
在保持相同提示质量的同时,它们通常会妨碍可读性,远不如前缀。

是的,我知道这很明显,但是很有可能没有想到。

请注意,匈牙利记法原本应像您本人一样受聘;参见that wikipedia entry中的“ Apps Hungarian”。