A "nicer" alternative to prefixing local variable names?

In a bunch of code that I'm writing I want to indicate that certain variables are to be used in a certain way, or have a certain characteristic to them. For the sake of discussion, suppose variables can be sweet, salty, sour or bitter.

What I use now is something like:

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

And I might also have sour_x, or salty_y etc.

Ideally - but this is not valid C++ - I would have been able to write something like this:

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

and this would nicely allow for a "sour x" and a "salty x" in the same function - if this syntax had been valid of course.

This may remind you of Hungarian Notation, except that it's not about variable types or sizes, and that the saltiness or sourness etc. are not inherent in x or in y - they only describe the way they're used.

Now, you could ask: "Ok, why not just put these in struct's?", that is, why not do:

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

But that preculdes defining additional salty/sour variables; and if I bunch them all at the beginning of the function, C-style, then it looks as though I indicate the variables are related, which is not necessarily the case.

What I currently do is just prefix the names: salty_x, sour_y. It's ugly but it works.

My question: Is there something else I could do which would look closer, in use, to my desired code, and at the same time not require too much "coding gymnastics"?


Due to popular demand: As a motivating/concretizing example, "salty" might mean "is uniform across all threads in a GPU warp, but possibly not across different warps" and "sour" might mean "is uniform across all threads in a CUDA kernel grid block / OpenCL workgroup when they reach this point in the code". But this is not a question about GPUs, CUDA, or OpenCL.

The hardest constraint was

Sometimes I even want to have a "sour x" and a "salty x" in the same function

So - the solution is the first usage of variadic template template parameter I ever made - so, here you are:

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

And the usage:

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

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

A, The ordinal number first, derived from this letter of the English alphabet, called a and written in the Latin script. NounEdit. a (plural aes). The name of the Latin  Free delivery on millions of items with Prime. Low prices across earth's biggest selection of books, music, DVDs, electronics, computers, software, apparel & accessories, shoes, jewelry, tools & hardware, housewares, furniture, sporting goods, beauty & personal care, groceries & just about anything else.

I'm sure you've checked all conventional approaches and neither was satisfactory... Lets turn to the magic then to achieve (I think) exactly what you want (c++17 will be needed):

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

One thing to be mentioned - gcc doesn't like the code though according to standard it should: [see this] [and that].

a, A definition is - the 1st letter of the English alphabet. How to use a in a sentence. a vs. an. Definition of a (Entry 2 of 13) 1 — used as a function word before singular nouns when the referent is unspecified a man overboard and before number collectives and some numbers a dozen 2 : the same birds of a feather swords all of a length

If I understand your edit correctly, you want to be able to define variables that behave exactly like int or float variables, but retain additional, ideally compile-time, information about their types.

The only thing I can't help you with is this:

Sometimes I even want to have a "sour x" and a "salty x" in the same function, which I could do if this syntax had been valid.

Personally, I would just prefix the variable name.

Anyway, here is an example of what you can do.

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.

Å, A or a is the first letter and the first vowel letter of the modern English alphabet and the ISO basic Latin alphabet. Its name in English is a plural aes. It is similar in  Translingual: ·The letter a with an acute accent.··The second letter of the Czech and Slovak alphabet, after a and before b

Postfixes. They usually hamper readibility a lot less than prefixes, while maintaining the same hinting quality.

Yes I know it's obvious, but it's very possible that it hadn't come to your mind.

And mind that the Hungarian Notation was originally meant to be employed pretty much as you would in your case; see "Apps Hungarian" in that wikipedia entry.

Lady Gaga, Bradley Cooper, A Star Is Born is the soundtrack album to the 2018 musical film of the same name, performed by its stars Lady Gaga and Bradley Cooper. It was released on  [Middle English, variant of an, an ; see an 1.] Usage Note: In writing, the form a is used before a word beginning with a consonant sound, regardless of its spelling (a frog, a university, a euphemism). The form an is used before a word beginning with a vowel sound (an orange, an hour).

A, Taking a trip? We have your travel plans covered. Flights · Hotels , Opens another site in a new window that may not meet accessibility guidelines. Cars , Opens  The letter Å (å in lower case) represents various (although often very similar) sounds in several languages. It is a separate letter in Swedish, Danish, Norwegian, Finnish, North Frisian, Walloon, Chamorro, Lule Sami, Skolt Sami, Southern Sami, and Greenlandic alphabets.

A, Try a love-story writing prompt to test your creativity and skills. FIND THE RIGHT PROMPT · thumbnail · GRATITUDE WRITING PROMPTS. Use these prompts  The <a> tag defines a hyperlink, which is used to link from one page to another. The most important attribute of the <a> element is the href attribute, which indicates the link's destination. By default, links will appear as follows in all browsers: An unvisited link is underlined and blue. A visited link is underlined and purple.

A Star Is Born (2018 soundtrack), Researchers found that adding six grams of spices to a meal high in fat and carbohydrates resulted in lower inflammation markers hours later. I had the problem that showing  instead of » , amd When Using this solution the problem solved but there is a php warning: Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at D:\Program Files\wamp\wamp\www\projects\kerala\kerala_public_html\edit\business_details.php:1) in D:\Program Files\wamp\wamp\www\projects\kerala\kerala_public_html\user

Comments
  • @Rakete1111 With the struct method, if you want to define a salty x somewhere and a salty y elsewhere but in the same scope, you would have conflicting declarations for the variable salty.
  • I don't think there are any difference between sour::x and sour_x in a local scope. Using namespace globally just because the name structure is complex and there are many names. In local scope, it's not the case.
  • I'm inclined to say "just use prefixes". I would need a concrete example of why you think it's ugly to try and find another solution.
  • You say "In a bunch of code that I'm writing I want to indicate that certain variables are to be used in a certain way, or have a certain characteristic to them." This is the definition of type: a set of variable that share some characteristic that can only be used in in a certain way (way=method).
  • Change your definition of ugliness. salty_x and sour_y look beautiful in my eyes when I'm coding in Python. In C++ I prefer saltyX and sourY. As long as they're in harmony with other variable names (all are snake_case or all are CamelCase) they look beautiful, ugliness comes when you break the harmony.
  • the usage looks like x and y are structures, not variables, and that x has a salty field and a sour field - and that's not what I want to convey with my code. But thanks for the effort.
  • +1 for effort. This is, umm, not so bad, I guess. It doesn't beat the prefixing in terms of readability though. Have you thought about a templated operator() for the context instead of get()? Perhaps that would allow for something like c<x,salty>() instead of c.get<x,salty>().
  • @einpoklum I think since c++17 it might actually work. Let me see.
  • @einpoklum Scratch that. It still doesn't and it's actually rational as it would see c as a variable template which can't be declared in non global (static) context...
  • @einpoklum this one has more readable syntax (I think best one you can actually get) ns->*label :) drawback - it uses macros
  • Thank you... I can't double-plus-1 you though.
  • No, you misunderstand me. The additional information needs to be visible to the programmer when referring to a variable, not in that variable's type.