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;
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].
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.
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.
Related
How to pass enum in a scope to another as function argument? As this is failing:
enum class L;
struct TestClass
{
void foo(L n)
{
int v = static_cast<int>(n);
int r[v] = { 9 };
cout << "\n" << v << "\n";
}
};
int main()
{
enum class L : int
{
A, B, C, D
};
TestClass main;
main.foo(L::D);
return 0;
}
error: cannot convert ‘main()::L’ to ‘L’
80 | main.foo(L::D);
| ~~~^
| |
| main()::L
How to solve this (in exact place, not move enum to a scope else) ?
How to solve this (in the exact place, not move enum to a scope else)?
Cast the enum while passing as a parameter.
main.foo(static_cast<int>(L::D));
Then your member function would be
void foo(int n)
{
std::vector<int> r(n, 9); // used `std::vector` instead of VLA
std::cout << "\n" << n << "\n";
}
(See sample code)
Note that the VLAs are not part of standard C++. Read more in the following post:
Why aren't variable-length arrays part of the C++ standard?
Prefer using std::vector as shown in the above code sample.
In a nutshell, the problem is that you have an enum that you want to use in two places. To me, the most natural solution to this is to put the enum in its own header file and use it where it is required.
// my_enum.h
#pragma once
enum class L : int {
A, B, C, D
};
// TestClass.h
#pragma once
// Can forward declare L so long as we define the functions in the same cpp
// If original enum is in a namespace it needs to be forward declared in the same namespace
enum class L;
struct TestClass {
void foo(L n);
};
// TestClass.cpp
#include "TestClass.h"
#include "my_enum.h"
void TestClass::foo(L n)
{
// do stuff with n
}
// main.cpp
#include "TestClass.h"
#include "my_enum.h"
int main(){
TestClass main;
main.foo(L::D);
return 0;
}
How to solve this (in exact place, not move enum to a scope else) ?
I'm conscious that I've answered the question in a way you did not want, but I do not see why you wouldn't want to put the enum in its own file. Avoiding this will lead to problems at some point. The consequence of JeJo's solution is that you could pass any old integer in to foo() - it is essentially decoupled from the enum. If the integer value is supposed to originate from the enum L: 1) it isn't obvious from the function signature and 2) it is prone to misuse i.e. someone passing in a value they shouldn't.
If putting the enum in its own header file is an unacceptable solution, I'd be interested to know why.
I want to create a class that contains a struct with a template. But it gives this error, and though I've seen other similar questions, I don't understand how or if I can declare this in a way that does not give this error. thanks for your help.
# include <iostream>
using namespace std;
template <class T>
class MyTmpl {
public:
MyTmpl() {}
T body;
};
struct s1_t {
std::string s;
int x;
};
MyTmpl<s1_t> myc();
myc.body.s = "s1";
myc.body.x = 7;
int main(int argc, char** argv) {
//std::cout << myc.body.s << ':' << myc.body.x << std::endl;
}
This gives:
x.cpp:24:1: error: 'myc' does not name a type
myc.body.s = "s1";
^
myc.body.s = "s1";
myc.body.x = 7;
Your immediate error is because you have this code where no code should be (at file level, outside of any function). You need to move it into main (or somewhere else that is is allowed to be, but probably main in this case).
The reason you see the does not name a type is simply because code is unexpected at that point so the compiler thinks you're trying to declare something (like, for example, int x;).
You'll get the same error with the code snippet:
//using nontype = int;
nontype x;
because nontype is not actually a type. If you however uncomment the using (a slightly more modern typedef), the nontype becomes a type and the error disappears.
Your second problem is that MyTmpl<s1_t> myc(); is a function declaration, something that would become evident if you included in your main:
auto x = myc();
The linker would then complain about the lack of a myc function definition. You should change it to:
MyTmpl<s1_t> myc; // without the ().
Your third problem is that, while you're using the C++ language, you're not quite yet using the C++ mindset. The whole point of classes is to encapsulate behaviour and state, something that's rather nullified if everything in your class is public :-)
Eventually (with experience), you'll get into the habit of privatising as much as possible, providing constructors, getters, setters, and so forth. Not an immediate issue for you but certainly something you'll want to work toward.
With those changes (other the the "C++ification") and uncommenting your output statement, the following resulting code compiles and runs fine, producing s1:7 as expected:
#include <iostream>
template <class T> class MyTmpl {
public:
MyTmpl() { }
T body;
};
struct s1_t {
std::string s;
int x;
};
MyTmpl<s1_t> myc; // variable, rather than function.
// code not allowed here.
int main() {
myc.body.s = "s1"; // code allowed here.
myc.body.x = 7;
std::cout << myc.body.s << ':' << myc.body.x << std::endl;
}
I want to programmatically retrieve the identifier of a C++ class instance at runtime. I'm aware that C++ doesn't support reflection yet, but is there any alternative solution out there?
For instance, given the following example:
class Foo {
Foo() {
auto name = reflect::getIdentifierName(this);
std::cout << name << std::endl;
}
};
void main() {
Foo my_obj;
}
Executing this program should print out "my_obj".
I'm looking for any utility library that I could use to implement this basic reflection function.
I'm particularly wondering if libclang can be used to extract such information - if so, any hint for how to build the reflect function to do this.
Yes, but this is implementation defined. Proceed at your own risk.
Yunnosch's suggestion sounds much more reasonable without more context.
#include <iostream>
#include <typeinfo>
class Foo {
public:
Foo() {
const char * const name = typeid(this).name();
std::cout << name << std::endl;
}
};
int main()
{
Foo my_obj;
}
why does this code work? with c++14
// Example program
#include <iostream>
#include <string>
using namespace std;
auto fun()
{
struct a
{
int num = 10;
a()
{
cout << "a made\n";
}
~a()
{
cout << "a destroyed\n";
}
};
static a a_obj;
return a_obj;
}
int main()
{
auto x = fun();
cout << x.num << endl;
}
how is the type a visible in main? if i change auto x= to a x= it obviously doesn't compile, but how does main know about the type a?
The static declaration is there since I was trying to test for something else but then I stumbled upon this behavior.
Running it here: https://wandbox.org/permlink/rEZipLVpcZt7zm4j
This is all surprising until you realize this: name visibility doesn't hide the type. It just hides the name of the type. Once you understand this it all makes sense.
I can show you this without auto, with just plain old templates:
auto fun()
{
struct Hidden { int a; };
return Hidden{24};
}
template <class T> auto fun2(T param)
{
cout << param.a << endl; // OK
}
auto test()
{
fun2(fun()); // OK
}
If you look closely you will see this is the same situation as yours:
you have a struct Hidden which is local to fun. Then you use an object of type Hidden inside test: you call fun which returns a Hidden obj and then you pass this object to the fun2 which in turn has no problem at all to use the object Hidden in all it's glory.
as #Barry suggested the same thing happens when you return an instance of a private type from a class. So we have this behavior since C++03. You can try it yourself.
C++14 is made to be more and more tolerant with auto. Your question is not clear, because you're not stating what the problem is.
Now let's tackle your question differently: Why does it not work with a x = ...?
The reason is that the struct definition is not in the scope of the main. Now this would work:
// Example program
#include <iostream>
#include <string>
using namespace std;
struct a
{
int num = 10;
};
auto fun()
{
static a a_obj;
return a_obj;
}
int main()
{
a x = fun();
cout << x.num << endl;
}
Now here it doesn't matter whether you use a or auto, because a is visible for main(). Now auto is a different story. The compiler asks: Do I have enough information to deduce (unambiguously) what the type of x is? And the answer is yes, becasue there's no alternative to a.
goals:
1. store constants with their assignments in a header
2. keep constants in a namespace (without using #define)
3. allow constants to be whatever precision is needed for the app
I am trying to keep all constants for my header only library in the same namespace. I decided to do away with #defines and do things the right way, such as using:
namespace studio
{
namespace constant
{
const char* WHITE_SPACE = "\n\r\t ";
}
}
The hope is to access this like so:
studio::constant::WHITE_SPACE
This is all fine and good, from what I have gathered, doing it this way creates one of these for each translation unit, potentially to be optimized down to a single instance during linking. Even if it is not optimized like that, it is probably okay in this case.
The trouble comes when I want to add other types besides const char * as constants. For example, say I want to allow a float type (double or float) as a constant, but I would like to do it as a template so I don't have to do something like:
namespace studio
{
namespace constant
{
const char* WHITE_SPACE = "\n\r\t ";
const float PI_FLOAT = 3.141592653589793;
const double PI_DOUBLE = 3.141592653589793;
}
}
So I tried using a templated class instead of a namespace, with static functions which return the static constant like so:
namespace studio
{
template <class FloatType = float>
class constant
{
public:
static const char* white_space_chars() {
static const char* whiteSpaceChars = "\n\r\t ";
return whiteSpaceChars;
}
static const FloatType pi() {
static const FloatType _pi = 3.141592653589793;
return _pi;
}
}
}
This would then be accessed this way: studio::constant<float>::pi()
But now I have the problem where I have to supply a template parameter if I want one of my const chars even though they have nothing to do with floats, they must be accessed like so:
studio::constant<float>::white_space_chars()
because
studio::constant::white_space_chars()
does not work, even though I specified a default template parameter, apparently that only works for classes. C++ does not allow defaults on function templates.
So now the only way I can see to get around this is to have studio::constant_char, studio::constant_float, studio::constant_int, etc. That is ridiculous, right?
Really all I want is to have my defines in a namespace...
Do you know a better way to do what I am trying to do, where variables of different types can be used template like in the studio::constant namespace without forcing the user of the library to specify the type for each template parameter? Preferably not using C++11 to be more backward compatible.
Move the template onto the static methods that actually use it:
namespace studio
{
class constant
{
public:
static const char* white_space_chars() {
return "\n\r\t ";
}
template <class FloatType = float>
static const FloatType pi() {
return FloatType(3.141592653589793);
}
};
}
Then you can do this:
float flt_pi = studio::constant::pi();
double dbl_pi = studio::constant::pi<double>();
I suppose this could be done by having an override-able define such as:
#ifndef STUDIO_FLOAT_TYPE
typedef float STUDIO_FLOAT_TYPE;
#endif
namespace studio
{
namespace constant
{
const char* WHITE_SPACE = "\n\r\t ";
const STUDIO_FLOAT_TYPE PI = 3.141592653589793;
}
}
Which would allow the user to override the float type before including the library header. At least there's only one define and it still has a default.
Because surely a define like this would be used in other headers, I suppose it might be nice to keep all the customizable defines in a single header that all the individual library headers refer to.
For future reference, in C++14 you can do:
template <typename T>
const T PI = T(3.141592653589793);
See variable templates.
As an example:
// header.h
namespace constant
{
template <typename T>
constexpr T PI = T(3.141592653589793);
}
void foo();
// foo.cpp
#include <iostream>
#include "header.h"
void foo() {
std::cout << constant::PI<int> << std::endl;
}
// main.cpp
#include <iostream>
#include "header.h"
int main()
{
std::cout << constant::PI<float> << std::endl;
foo();
}
This gives the output:
3.14159
3