在我正在撰写的一堆代码中,我想表明某些变量将以某种方式使用,或者具有某些特征。为了便于讨论,假设变量可以是甜的,咸的,酸的或苦的。
我现在使用的是:
int foo() {
int salty_x;
int sour_y;
do_stuff_with(salty_x,sour_y);
}
我可能还有sour_x
或salty_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_x
,sour_y
。这很丑,但它确实有效。
我的问题:我还能做些什么,在使用中看起来更接近我想要的代码,同时又不需要太多的“编码体操”?
由于受欢迎的需求:作为激励/具体化的例子,“咸”可能意味着“GPU扭曲中的所有线程都是统一的,但可能不会跨越不同的扭曲”和“酸”可能意味着“在所有线程中均匀”在CUDA内核网格块/ OpenCL工作组中,当它们到达代码中的这一点时“。但这不是关于GPU,CUDA或OpenCL的问题。
答案 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)
如果我正确理解您的编辑,您希望能够定义与int
或float
变量完全相同的变量,但保留有关其类型的其他理想编译时信息。< / 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; }
};
答案 3 :(得分:0)
后缀。
在保持相同提示质量的同时,它们通常会妨碍可读性,远不如前缀。
是的,我知道这很明显,但是很有可能没有想到。
请注意,匈牙利记法原本应像您本人一样受聘;参见that wikipedia entry中的“ Apps Hungarian”。