I have a class with a reference and want a getter that returns a pointer.
class X {
std::string& text;
public:
auto GetText() -> decltype(text) * { return &text); // doesn't work
X(std::string& text): text(text) {}
};
The easy way is to pass a pointer to this class. But if I pass a reference, can I get a pointer with a getter?
Edit: here is the error message
error: cannot declare pointer to 'std::__cxx11::string& {aka class std::__cxx11::basic_string<char>&}'
auto GetText() -> decltype(text) * { return &text);
^
Firstly,
auto GetText() -> decltype(text) * { return &text); // doesn't work
is a positively abominable way to declare this signature. Prefer
std::string* GetText(){ return &text);
or even just
auto GetText(){ return &text);
But this isn't code review.
The problem here is that you're asking for a pointer to the declared type of the text member variable which is a string reference (std::string&). From the comment section, it seems you were unaware that decltype respects the 'reference'ness, 'const'ness, and 'volatile'ness of its argument.
You cannot have a pointer to a reference in C++, e.g. std::string&* is malformed. Calling to std::remove_reference_t should resolve that issue, e.g.
auto GetText() -> std::remove_reference_t<decltype(text)> * { return &text);
However, in this case, auto would have correctly deduced your type anyway, so your explicit declaration is unnecessary.
I've made a test program for my initial problem. The program has a class with a pointer and a getter that returns a reference and a second class with a reference and a getter that returns a pointer.
And it seems that -> std::remove_reference_t<decltype(text)> can be substituted with -> decltype(&text).
Feel free to comment.
// g++ main.cpp -o test_reference_pointer && strip -s test_reference_pointer && ./test_reference_pointer
#include <iostream>
// A class with a pointer and a getter that returns a reference.
class A {
std::string *text;
public:
std::string& GetText_old_way() { return *text; }
auto GetText_pure_auto() { return *text; }
auto GetText_pointer_arithmetic() -> decltype(*text) & { return *text; }
public:
A(std::string *text): text(text) {}
};
// A class with a reference and a getter that returns a pointer.
class B {
std::string& text;
public:
std::string *GetText_old_way() { return &text; }
auto GetText_pure_auto() { return &text; }
auto GetText_pointer_arithmetic() -> decltype(&text) { return &text; }
auto GetText_remove_reference() -> std::remove_reference_t<decltype(text)> * { return &text; }
public:
B(std::string& text): text(text) {}
};
int main() {
std::string text = "hello, world";
{//TEST
A a(&text);
unsigned int i{0};
std::cout << "-- Test 1:"<< std::endl;
++i; std::cout << i << ". " << a.GetText_old_way() << std::endl;
++i; std::cout << i << ". " << a.GetText_pointer_arithmetic() << std::endl;
++i; std::cout << i << ". " << a.GetText_pure_auto() << std::endl;
std::cout << std::endl;
}
{//TEST
B b(text);
unsigned int i{0};
std::cout << "-- Test 2:"<< std::endl;
++i; std::cout << i << ". " << *b.GetText_old_way() << std::endl;
++i; std::cout << i << ". " << *b.GetText_pointer_arithmetic() << std::endl;
++i; std::cout << i << ". " << *b.GetText_remove_reference() << std::endl;
++i; std::cout << i << ". " << *b.GetText_pure_auto() << std::endl;
std::cout << std::endl;
}
return 0;
}
Related
is there any mechanism with elegant API to handle functions of any type?
I mean a class that automagically detects type of a function (its return type, arguments, if it is a class member, a const etc), something that I could easily use to handle any kind of events, like in the example below:
class Abc
{
public:
void aFunc() { std::cout << "a()" << std::endl; }
void cFunc(int x, char y) { std::cout << "c(" << x << ", " << y << ")" << std::endl; }
};
void bFunc(int x) { std::cout << "b(" << x << ")" << std::endl; }
int main()
{
Abc abc;
EventHandler a = abc.aFunc;
EventHandler b = bFunc;
EventHandler c = abc::cFunc;
a();
b(123);
c(456789, 'f');
std::cout << "Done." << std::endl;
return 0;
}
The std::function and std::bind can be used internally, but the bind should be done automatically.
I want to make a function that can wrap any lambda to log start/end calls on it.
The code below works except for:
any lambda that has captures
any lambda that returns void (although this can easily be fixed by writing a second function)
#include <iostream>
#include <functional>
template <class T, class... Inputs>
auto logLambda(T lambda) {
return [&lambda](Inputs...inputs) {
std::cout << "STARTING " << std::endl;
auto result = lambda(inputs...);
std::cout << "END " << std::endl;
return result;
};
}
int main() {
int a = 1;
int b = 2;
// works
auto simple = []() -> int {
std::cout << "Hello" << std::endl; return 1;
};
logLambda(simple)();
// works so long as explicit type is declared
auto with_args = [](int a, int b) -> int {
std::cout << "A: " << a << " B: " << b << std::endl;
return 1;
};
logLambda<int(int, int), int, int>(with_args)(a, b);
// Does not work
// error: no matching function for call to ‘logLambda<int(int), int>(main()::<lambda(int)>&)’
auto with_captures = [&a](int b) -> int {
std::cout << "A: " << a << " B: " << b << std::endl;
return 1;
};
logLambda<int(int), int>(with_captures)(b);
}
Is there any way to do this? Macros are also acceptable
Use Raii to handle both void and non-void return type,
and capture functor by value to avoid dangling reference,
and use generic lambda to avoid to have to specify argument your self
It results something like:
template <class F>
auto logLambda(F f) {
return [f](auto... args) -> decltype(f(args...)) {
struct RAII {
RAII() { std::cout << "STARTING " << std::endl; }
~RAII() { std::cout << "END " << std::endl; }
} raii;
return f(args...);
};
}
Call look like:
const char* hello = "Hello";
logLambda([=](const char* s){ std::cout << hello << " " << s << std::endl; })("world");
Demo
That code has undefined behavior.
auto logLambda(T lambda) {
return [&lambda]
You are capturing local parameter by reference.
I'd like to take out members of a temporary without unnecessary moving or copying.
Suppose I have:
class TP {
T _t1, _t2;
};
I'd like to get _t1, and _t2 from TP(). Is it possible without copying/moving members?
I've tried with tuples and trying to "forward" (I don't think it's possible) the members, but the best I could get was a move, or members dying immediately.
In the following playground using B::as_tuple2 ends up with members dying too soon, unless the result is bound to a non-ref type, then members are moved. B::as_tuple simply moves is safe with auto on client side.
I suppose this should be technically possible, since the temporary dies immediately, and the member do die while they could bound to variables on the calling site (Am I wrong?), and structured binding of a similar struct works as intended.
Is it possible to extend/pass life of the member onto an outside variable, or elide the move/copy? I need it with c++14 version, but I couldn't get it to work on c++17 either, so I am interested in both.
Playground:
#include <tuple>
#include <iostream>
using std::cout;
class Shawty {
/**
* Pronounced shouty.
**/
public:
Shawty() : _id(Shawty::id++) {cout << _id << " ctor\n"; }
Shawty(Shawty && s) : _id(Shawty::id++) { cout << _id << " moved from " << s._id << "\n"; }
Shawty(const Shawty & s) : _id(Shawty::id++) { cout << _id << " copied from " << s._id << "\n"; }
Shawty& operator=(Shawty && s) { cout << _id << " =moved from " << s._id << "\n"; return *this;}
Shawty& operator=(Shawty & s) { cout << _id << " =copied from " << s._id << "\n"; return *this;}
~Shawty() {cout << _id << " dtor\n"; }
int _id;
static int id;
};
int Shawty::id = 0;
class B {
public:
auto as_tuple() && {return std::make_tuple(std::move(_s1), std::move(_s2));}
auto as_tuple2() && {return std::forward_as_tuple(std::move(_s1), std::move(_s2));}
private:
Shawty _s1, _s2;
};
struct S {
Shawty _s1, _s2;
};
int main() {
std::cout << "----------\n";
auto [s1, s2] = B().as_tuple2();
std::cout << "---------\n";
auto tpl1 = B().as_tuple2();
std::cout << "----------\n";
std::tuple<Shawty, Shawty> tpl2 = B().as_tuple2();
std::cout << "----------\n";
std::cout << std::get<0>(tpl1)._id << '\n';
std::cout << std::get<1>(tpl1)._id << '\n';
std::cout << std::get<0>(tpl2)._id << '\n';
std::cout << std::get<1>(tpl2)._id << '\n';
std::cout << s1._id << '\n';
std::cout << s2._id << '\n';
std::cout << "--struct--\n";
auto [s3, s4] = S{};
std::cout << s3._id << '\n';
std::cout << s4._id << '\n';
std::cout << "----------\n";
return 0;
}
No. It is not possible to extend the lifetime of more than one member beyond the lifetime of the super object.
So, the only way to "get" members without copying is to keep the super object alive, and refer to them:
// member function
auto as_tuple3() & {
return std::make_tuple(std::ref(_s1), std::ref(_s2));
}
// usage
B b;
auto [s1, s2] = b.as_tuple3();
An example of extending lifetime of the object by binding a reference to a single member. Note that this requires the member to be accessible from where the reference is bound (not the case in your example, where the member is private):
auto&& s1 = B{}._s1;
Add support for structured binding to your B type.
class B {
public:
template<std::size_t I, class Self,
std::enable_if_t< std::is_same_v<B, std::decay_t<Self>>, bool> = true
>
friend constexpr decltype(auto) get(Self&& self) {
if constexpr(I==0)
{
using R = decltype(std::forward<Self>(self)._s1)&&;
return (R)std::forward<Self>(self)._s1;
}
else if constexpr(I==1)
{
using R = decltype(std::forward<Self>(self)._s2)&&;
return (R)std::forward<Self>(self)._s2;
}
}
private:
Shawty _s1, _s2;
};
namespace std {
template<>
struct tuple_size<::B>:std::integral_constant<std::size_t, 2> {};
template<std::size_t N>
struct tuple_element<N, ::B>{using type=Shawty;};
}
Test code:
int main() {
std::cout << "----------\n";
{
auto&& [s1, s2] = B();
}
}
output:
----------
0 ctor
1 ctor
1 dtor
0 dtor
Live example.
This is the best I can do. Note that s1 and s2 are references into a lifetime-extended version of B.
Is it possible to call this member int MyClass::get(int key) const instead of the int& MyClass::get(int key)? In other words, where in the C++ source codes, a value can be used but not a reference?
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int input) : i(input) {};
int i;
int get(int key) const {
std::cout << "int get(int key) const " << key << std::endl;
return i;
}
int& get(int key) {
std::cout << "int& get(int key) " << key << std::endl;
return i;
}
};
void dummy(const int helpme)
{
std::cout << helpme << std::endl;
}
int main() {
// your code goes here
MyClass abc(6);
std::cout << abc.get(13) << std::endl;
int result = (int)abc.get(16);
dummy(abc.get(18));
return 0;
}
The simplest solution is to use a const & to your variable. Two simple ways are
const auto & abc_const = abc;
std::cout << abc_const.get(13) << std::endl;
or
std::cout << static_cast<const MyClass&>(abc).get(13) << std::endl;
Edit: It looks like you were trying to choose an overload based on the return type, based on these two lines :
int result = (int)abc.get(16);
dummy(abc.get(18));
See this answer explaining how the return type is never used during overload resolution.
First off: I know that it is generally a bad idea to change an object's class, but I'm implementing my own programming language, and it has variables that can contain values of any type, and even change their type at will, so please assume I'm not a beginner not understanding OO basics.
Currently, I implement my variant variables in C. Each one has a pointer to a table of function pointers, containing functions like SetAsInt(), SetAsString() etc., followed by what would be instance variables in C++. All objects are the same size.
When a variable contains a string and someone assigns an Int to it, I manually call the destructor, change the table of function pointers to point to the table used for variadic int values, and then set its int instance variable.
This is a bit hard to maintain, as every time I add a new type, I have to add a new table of function pointers and fill out all the function pointers in it. Structs of function pointers seem to be very badly type-checked, and missing fields don't lead to complaints, so I can easily accidentally forget one pointer in the list and get interesting crashes. Also, I have to repeat all the function pointers that are the same in most types.
I'd like to implement my variadic types in C++ instead, where a lot of this type-checking and inheriting default behaviours is done for me by the compiler. Is there a safe way to do this?
PS - I know I could create a wrapper object and use new to allocate a new object, but I can't have the additional extra allocation overhead for every int variable on the stack.
PPS - The code needs to be portable across Linux, Mac, iOS and Windows for now, but if someone has a standard C++ solution, that would be even better.
PPPS - The list of types is extensible, but predetermined at compile-time. The base layer of my language defines just the basic types, but the host application my language is compiled into adds a few more types.
Usage Example:
CppVariant someNum(42); // Creates it as CppVariantInt.
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This calls destructor on CppVariantInt and constructor on CppVariantDouble(12.34).
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl; // GetAsInt() on a CppVariantDouble() rounds, or whatever.
(Imagine that beyond double and int, there would be other types in the future, like strings or booleans, but the caller of GetAsInt()/SetAsInt() shouldn't have to know what it is stored as, as long as it can be converted at runtime)
Here is a solution based on type-erasure, union and template specializations.
I'm not sure it fits your requirements.
Anyway, here is what it gets:
Anything is placed on the dynamic storage
No hierarchy required
You can easily improve it further to reduce the amount of code, but this aims to serve as a base point from which to start.
It follows a minimal, working example based on the intended use in the question:
#include<iostream>
class CppVariant {
union var {
var(): i{0} {}
int i;
double d;
};
using AsIntF = int(*)(var);
using AsDoubleF = double(*)(var);
template<typename From, typename To>
static To protoAs(var);
public:
CppVariant(int);
CppVariant(double);
int getAsInt();
double getAsDouble();
void setAsInt(int);
void setAsDouble(double);
private:
var data;
AsIntF asInt;
AsDoubleF asDouble;
};
template<>
int CppVariant::protoAs<int, int>(var data) {
return data.i;
}
template<>
int CppVariant::protoAs<double, int>(var data) {
return int(data.d);
}
template<>
double CppVariant::protoAs<int, double>(var data) {
return double(data.i);
}
template<>
double CppVariant::protoAs<double, double>(var data) {
return data.d;
}
CppVariant::CppVariant(int i)
: data{},
asInt{&protoAs<int, int>},
asDouble{&protoAs<int, double>}
{ data.i = i; }
CppVariant::CppVariant(double d)
: data{},
asInt{&protoAs<double, int>},
asDouble{&protoAs<double, double>}
{ data.d = d; }
int CppVariant::getAsInt() { return asInt(data); }
double CppVariant::getAsDouble() { return asDouble(data); }
void CppVariant::setAsInt(int i) {
data.i = i;
asInt = &protoAs<int, int>;
asDouble = &protoAs<int, double>;
}
void CppVariant::setAsDouble(double d) {
data.d = d;
asInt = &protoAs<double, int>;
asDouble = &protoAs<double, double>;
}
int main() {
CppVariant someNum(42);
std::cout << "Original int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsInt(700);
std::cout << "Changed int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsDouble(12.34);
std::cout << "Converted to Double: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
}
On a lark, I tried using placement new to do this, and I have ... something ... It compiles, it does the job, but I'm not sure if it's an improvement over pure C. Since I can't have a union of C++ objects, I create a CPPVMAX() macro to pass the largest sizeof() of all subclasses as the size to mBuf[], but that's not really pretty either.
#include <iostream>
#include <string>
#include <cmath>
#define CPPVMAX2(a,b) (((a) > (b)) ? (a) : (b))
#define CPPVMAX3(a,b,c) CPPVMAX2((a),CPPVMAX2((b),(c)))
using namespace std;
class CppVariantBase
{
public:
CppVariantBase() { cout << "CppVariantBase constructor." << endl; }
virtual ~CppVariantBase() { cout << "CppVariantBase destructor." << endl; }
virtual int GetAsInt() = 0;
virtual double GetAsDouble() = 0;
virtual void SetAsInt( int n );
virtual void SetAsDouble( double n );
};
class CppVariantInt : public CppVariantBase
{
public:
CppVariantInt( int n = 0 ) : mInt(n)
{
cout << "CppVariantInt constructor." << endl;
}
~CppVariantInt() { cout << "CppVariantInt destructor." << endl; }
virtual int GetAsInt() { return mInt; }
virtual double GetAsDouble() { return mInt; }
virtual void SetAsInt( int n ) { mInt = n; }
protected:
int mInt;
};
class CppVariantDouble : public CppVariantBase
{
public:
CppVariantDouble( double n = 0 ) : mDouble(n)
{
cout << "CppVariantDouble constructor." << endl;
}
~CppVariantDouble()
{
cout << "CppVariantDouble destructor." << endl;
}
virtual int GetAsInt()
{
if( int(mDouble) == mDouble )
return mDouble;
else
return round(mDouble);
}
virtual double GetAsDouble() { return mDouble; }
virtual void SetAsDouble( int n ) { mDouble = n; }
protected:
double mDouble;
};
class CppVariant
{
public:
CppVariant( int n = 0 ) { new (mBuf) CppVariantInt(n); }
~CppVariant() { ((CppVariantBase*)mBuf)->~CppVariantBase(); }
operator CppVariantBase* () { return (CppVariantBase*)mBuf; }
CppVariantBase* operator -> () { return (CppVariantBase*)mBuf; }
protected:
uint8_t mBuf[CPPVMAX3(sizeof(CppVariantBase),sizeof(CppVariantInt),sizeof(CppVariantDouble))];
};
void CppVariantBase::SetAsInt( int n )
{
this->~CppVariantBase();
new (this) CppVariantInt(n);
}
void CppVariantBase::SetAsDouble( double n )
{
this->~CppVariantBase();
new (this) CppVariantDouble(n);
}
int main(int argc, const char * argv[]) {
CppVariant someNum(42);
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This changes the class to CppVariantDouble.
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
return 0;
}