I have a namespace, N0, that has sub-namespaces including N1. The calling code only knows about the outer namespace. I'd like to write a function in the outer namespace that returns a std::unique_ptr<N1::T> where that result is consumed elsewhere in N0. However, the caller shouldn't know about N1. What I'd like to do is something like:
// N0.h
namespace N0 {
typename T; // This isn't real C++.
std::unique_ptr<T> foo();
void bar(std::unique_ptr<T>&&);
}
// N0.cpp
#include "N1.h" // Get N1::T
namespace N0 {
typedef N1::T T;
...
}
That is, I'd like to expose a type that the caller can't see but internally I'd like to actually use a type in a different namespace. This way elsewhere someone could just forward-declare namespace N0 { class T; } without having to know that T is actually in N1.
I could move T itself into N0, but it really belongs in N1.
I could wrap T with a dummy class in N0, but that's ugly, and the pointer should basically do that.
I could probably make a class N0::T that subclasses N1::T, but that seems icky too.
Is there no way for N0 to forward declare that "I have a type and you don't need to know what it is" and have that type actually be in a different namespace? Put another way: Why is class C; class C{}; legal but class C; typedef int C; is illegal? (Likewise class C; using C = int; or typedef C; typedef int C;.) They seem fundamentally the same to me and I can't think of a clever template trick to get around it. The only difference I can think of is that the typedef version wouldn't be subject to Koenig lookup.
I mean you could do this:
// N0.h
namespace N0 {
std::unique_ptr<T> foo();
void bar(std::unique_ptr<T>&&);
}
// N0.cpp
namespace N0 {
typedef N1::T t;
}
#include "N0.h"
namespace N0 {
// whatever...
}
In the situation you have described, the foo should be implemented as a template function:
namespace N0 {
template <typename T>
std::unique_ptr<T> foo(){...};
template <typename T>
void bar(std::unique_ptr<T>&&){...};
}
And you should using a wrap/overload function to do the final trick:
namespace N0 {
std::unique_ptr<N1::T> foo() { return foo<N1::T>(); }
//for bar there is no need to wrap, cause the T could be resolved by parameters.
}
Here's the best I've come up with, which seems to work. I still feel like there should be a way to not use "tricks" to make N1::T fully hidden from callers:
// N0.h
#pragma once
#include <memory>
namespace N0 {
struct OpaqueObject { virtual ~OpaqueObject() {} };
std::unique_ptr<OpaqueObject> foo();
void bar(std::unique_ptr<OpaqueObject>&&);
}
//N0.cpp
#include "N1.h"
namespace N0 {
std::unique_ptr<OpaqueObject> foo() { return std::unique_ptr<N1::T>(new N1::T()); }
void bar(std::unique_ptr<OpaqueObject> &&) {}
}
// N1.h
#pragma once
#include "N0.h"
namespace N1 {
class T : public N0::OpaqueObject {};
}
// test.cpp
#include "N0.h"
int main() {
auto x = N0::foo();
N0::bar(std::move(x));
}
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.
I have many types of game-object that are related together is some ways.
All relations is implemented by Map<K1,K2>.
#include <vector>
using namespace std;
template<class K1,class K2> class Map{ //N:N relation
public: std::vector<K2*> getK2(K1* k1){/* some code */return std::vector<K2*>();}
public: std::vector<K1*> getK1(K2* k2){/* some code */return std::vector<K1*>();}
//... various function ...
};
Here is the hub class GameRelation that facilitates all relation query :-
(just an example, no need to pay attention to all detail)
class Human{}; class House{}; class Dog{};
class GameRelation{
public:
#define RELATION(A,B,EnumName) Map<A,B> Map##EnumName; \
enum EnumName##Enum{EnumName}; \
std::vector<B*> getAllRight(EnumName##Enum e,A* a){ \
return Map##EnumName.getK2(a); \
}
//... various function ...
RELATION(Human,House,Own)
//I can insert any relation that I want
};
The above macro expands into something like :-
Map<Human,House> MapOwn;
enum OwnEnum{Own};
std::vector<House*> getAllRight(OwnEnum e,Human* a){
return MapOwn.getK2(a);
}
Here is how it can be used (full demo):-
int main() {
GameRelation gameRelation;
std::vector<House*> houses=gameRelation.getAllRight(GameRelation::Own,new Human());
//get all "House" that is "Own" by a "Human"
return 0;
}
After some testing, it works good. Everyone is happy with the magical result.
However, my conscious tell me that it is a hack.
It is also a little bad for content-assist (e.g. intellisense) and automatic refactoring.
I also need the awesome hacking X-MACRO if I want to move their implementation to .cpp.
Question:
Is there any elegant (less hack) way? What is it?
"No" can be a valid answer.
Is X-MACRO the (professional) way to go when I need such (strange) feature?
struct GameRelation{
template <typename A, typename B>
struct Relation {
std::vector<B*> getAllRight(A* a) {
return map.getK2(a);
}
private:
Map<A, B> map;
};
Relation<Human, House> own;
};
int main() {
GameRelation gameRelation;
std::vector<House*> houses = gameRelation.own.getAllRight(new Human());
}
I have the following situation: Depending on some parameter that my function takes it have to create different types:
I want to do something like this:
if(variant==1){
#define my_type int;
}
else{
#define my_type double;
}
cout<<sizeof(my_type);
and then use my_type in my further code.
So, that in case of variant=1 sizeof(my_type) gives 4 and for variant=2 it gives 8.
How can this be done? Either in this manner or another.
Thanks.
I agree with #Magnus Hoff in that what you asked cannot be done. But there are two approximations.
Option 1: make variant a macro.
#ifdef variant
# define my_type int
#else
# define my_type double
#endif
Option 2: use template function.
Instead of
void func(int variant) {
if (variant==1)
#define my_type int
else
#define my_type double
my_type ...
}
do this:
template<typename my_type> void func() {
my_type ...
}
Replace this:
if(variant==1){
#define my_type int;
}
else{
#define my_type double;
}
cout<<sizeof(my_type);
… with this:
template< class Type >
void foo()
{
// ...
cout<<sizeof(Type);
}
// ...
if( variant==1 )
{
foo<int>();
}
else
{
foo<double>();
}
Note that a runtime value can't affect compile time decisions. Without a time travel device.
I have a template class. Since the templates are processed during compile time, is it possible to compare the template parameter during compile time and use the preprocessor to add specific code? Something like this:
template<class T>
class MyClass
{
public:
void do()
{
#if T is equal to vector<int>
// add vector<int> specific code
#if T is equal to list<double>
// add list<double> specific code
#else
cout << "Unsupported data type" << endl;
#endif
}
};
How can I compare the template types to another type during compile time as shown in the example above? I do not want to add specific subclasses that handle specific types.
First things first - do is a keyword, you can't have a function with that name.
Secondly, preprocessor runs before the compilation phase, so using stuff from templates in it is out of the question.
Finally, you can specialize only a part of a class template, so to speak. This will work:
#include <iostream>
#include <vector>
#include <list>
template<class T>
class MyClass
{
public:
void run()
{
std::cout << "Unsupported data type" << std::endl;
}
};
template<>
void MyClass<std::vector<int>>::run()
{
// vector specific stuff
}
template<>
void MyClass<std::list<double>>::run()
{
// list specific stuff
}
Live demo.