Define object from template type - c++

is there any way to define an object in a way similar to the line below???
template<typename T>
struct A {
T *data;
//...
typedef T data_type;
};
int main() {
A<int>::data_type a; // ok
A<int> obj;
obj.data_type b; // <-- is it possible to do something like this??
}
Thanks!
Massimo

You can use decltype on expressions. The code for your case would be:
decltype(obj)::data_type b;

From C++11 onwards it is possible:
decltype(obj) is evaluated at compile-time and is the type of obj. It can be used whenever a type is used.
So you could write decltype(obj)::data_type b;
decltype is a keyword and is particularly useful in generic programming.

This seems to work fine; use decltype() for c++11; you can try typeof() pre c++11
typeof() in gcc: https://gcc.gnu.org/onlinedocs/gcc/Typeof.html
#include <iostream>
using namespace std;
template<typename T>
struct A {
T *data;
//...
typedef T data_type;
};
int main() {
A<int>::data_type a; // ok
A<int> obj;
decltype(obj)::data_type b; // <-- is it possible to do something like this??
}

Related

How to make void(*)(...) as a struct member

for a demo code
#include <iostream>
#include <map>
#include <vector>
using namespace std;
typedef struct Student
{
public:
Student(){}
~Student(){}
static void print(int a,int b){printf("age is a\n");}
}Student;
int main(){
void (*p)(int, int) = &Student::print;
vector<void(*)(int,int)> tt;
tt.push_back(p);
tt[0](1,1);
return 0;
}
when I want to make the void(*)(int,int) as a struct member, like
struct void_func_st{
void(*)(int,int) f;
int a;
};
the code is wrong. I don't know whether the struct could be made actually as I'm not familiar with how the void(*)(...) works. Or I just didn't get the right way to make void(*)(...) as a struct member. Can anyone give some advice?
It would be (as you do for local variable p in main)
void(*f)(int,int);
As note, typedef/using or some "wrapper" might help to have more regular syntax, for example:
using bin_func = void(int, int);
bin_func* f2;
std::add_pointer_t<void(int, int)> f3;
std::type_identity_t<void(int, int)>* f4;
Use std::function and forget about the confusing function pointer syntax:
struct void_func_st {
std::function<void(int,int)>; f;
int a;
};
Even better, introduce a nice alias for it:
using MyFunction = std::function<void(int,int)>;

Forward declaring a hidden typedef in C++

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

`std::pair` `second` has incomplete type with `unordered_map` tree

I was reviewing some older code of mine and I saw the code using pointers to implement a tree of Variant objects. It is a tree because each Variant can contain an unordered_map of Variant*.
I looked at the code and wondered why isn't it just using values, a std::vector<Variant>, and std::unordered_map<std::string, Variant>, instead of Variant*.
So I went ahead and changed it. It seemed okay except one thing, I got errors:
/usr/local/include/c++/6.1.0/bits/stl_pair.h:153:11: error: 'std::pair<_T1, _T2>::second' has incomplete type
_T2 second; /// #c second is a copy of the second object
^~~~~~ main.cpp:11:8: note: forward declaration of 'struct Variant'
struct Variant
^~~~~~~
So I figured I could trick the compiler into delaying the need to know that type, which didn't work either.
Working Not Working! (MCVE)
I thought this worked earlier but it actually doesn't, I forgot ::type on the using HideMap...
#include <vector>
#include <unordered_map>
#include <iostream>
template<typename K, typename V>
struct HideMap
{
using type = std::unordered_map<K, V>;
};
struct Variant
{
using array_container = std::vector<Variant>;
// Does not work either
using object_container = typename HideMap<std::string, Variant>::type;
// Fails
//using object_container = std::unordered_map<std::string, Variant>;
private:
union Union
{
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
Union data;
bool weak;
};
int main()
{
Variant v;
std::cout << "Works" << std::endl;
}
So, my question is, why does it work okay for vector and not unordered_map?
If the problem is the inability to use incomplete types, is there a way to delay the instantiation of the unordered_map? I really don't want every object property to be a separate new allocation.
This uses placement new to defer the initialization of the Union to the constructor where Variant is a complete type. You need to reinterpret_cast everywhere you need to use the Union. I made an effort to not have any strict-alignment violations.
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
struct Variant {
Variant();
~Variant();
private:
std::aligned_union<0, std::vector<Variant>,
std::unordered_map<std::string, void *>,
std::int64_t>::type data;
};
namespace Variant_detail {
using array_container = std::vector<Variant>;
using object_container = std::unordered_map<std::string, Variant>;
union Union {
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
}
Variant::Variant() {
//make sure that std::unordered_map<std::string, Variant> is not too large
static_assert(sizeof(std::unordered_map<std::string, Variant>) <=
sizeof data, "Variant map too big");
static_assert(alignof(std::unordered_map<std::string, Variant>) <=
alignof(decltype(data)), "Variant map has too high alignment");
auto &my_union = *new (&data) Variant_detail::Union;
my_union.vint = 42;
}
Variant::~Variant() {
reinterpret_cast<Variant_detail::Union &>(data).~Union();
}
int main() {
Variant v;
std::cout << "Works" << std::endl;
}

A confusing typedef involves class scope

I'm reading code of a C++ project and it contains some code of the following form:
namespace ns {
class A {};
class B {};
}
struct C {
typedef ns::A* ns::B::* type;
};
Can someone explain the meaning of the typedef line? type seems to be some kind of pointer to member of ns::B which points to ns::A, but I'm not sure.
Class A and B in the real code are not empty, but I think it's not relevant here. And here is a live example.
ns::B::*
is a pointer-to-member-variable of B. Then ns::A* is its type.
So the whole declaration means
pointer-to-member-variable of B of type ns::A*
The answer by #vsoftco already answers the core of the question. This answer shows how one might use such a typedef.
#include <iostream>
#include <cstddef>
namespace ns {
struct A {};
struct B
{
A* a1;
A* a2;
};
}
struct C {
typedef ns::A* ns::B::*type;
};
int main()
{
C::type ptr1 = &ns::B::a1;
C::type ptr2 = &ns::B::a2;
ns::B b1;
b1.*ptr1 = new ns::A; // Samething as b1.a1 = new ns::A;
return 0;
}

How to have a c++ object with a method that takes argument the enclosing class?

I am trying to figure out if there's any known pattern/idiom in c++ for what I am trying to do here. Class A must be composed of an object that has a function whose argument must also be of type A. The following code doesn't compile since typeid may not be used in a constant expression. Any suggestions?
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; }
};
class A {
B<typeid(A)> b;
};
int main()
{
A k;
}
Your stated requirements don't need templates at all, just a forward declaration:
#include <iostream>
class A; // forward declare A
struct B {
int f(A &i); // declaration only, definition needs the complete type of A
};
class A {
B b;
};
int B::f(A &i) { std::cout << "Hello\n"; } // define f()
int main()
{
A k;
}
You are looking for B<A> b; The following program compiles without error or warning on g++ 4.4.3.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; return 0; }
};
class A {
public:
B<A> b;
};
int main()
{
A k;
return k.b.f(k);
}
Note: If you are using templates only to avoid forward declaration, my solution is wrong. But, I'll leave it here in case you are using templates for some other legitimate reason.