compile time if && return string reference optimization
- by Truncheon
Hi.
I'm writing a series classes that inherit from a base class using virtual. They are INT, FLOAT and STRING objects that I want to use in a scripting language. I'm trying to implement weak typing, but I don't want STRING objects to return copies of themselves when used in the following way (instead I would prefer to have a reference returned which can be used in copying):
a = "hello ";
b = "world";
c = a + b;
I have written the following code as a mock example:
#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
std::string dummy("<int object cannot return string reference>");
struct BaseImpl
{
virtual bool is_string() = 0;
virtual int get_int() = 0;
virtual std::string get_string_copy() = 0;
virtual std::string const& get_string_ref() = 0;
};
struct INT : BaseImpl
{
int value;
INT(int i = 0) : value(i)
{
std::cout << "constructor called\n";
}
INT(BaseImpl& that) : value(that.get_int())
{
std::cout << "copy constructor called\n";
}
bool is_string() { return false; }
int get_int()
{
return value;
}
std::string get_string_copy()
{
char buf[33];
sprintf(buf, "%i", value);
return buf;
}
std::string const& get_string_ref()
{
return dummy;
}
};
struct STRING : BaseImpl
{
std::string value;
STRING(std::string s = "") : value(s)
{
std::cout << "constructor called\n";
}
STRING(BaseImpl& that)
{
if (that.is_string())
value = that.get_string_ref();
else
value = that.get_string_copy();
std::cout << "copy constructor called\n";
}
bool is_string() { return true; }
int get_int()
{
return atoi(value.c_str());
}
std::string get_string_copy()
{
return value;
}
std::string const& get_string_ref()
{
return value;
}
};
struct Base
{
BaseImpl* impl;
Base(BaseImpl* p = 0) : impl(p) {}
~Base() { delete impl; }
};
int main()
{
Base b1(new INT(1));
Base b2(new STRING("Hello world"));
Base b3(new INT(*b1.impl));
Base b4(new STRING(*b2.impl));
std::cout << "\n";
std::cout << b1.impl->get_int() << "\n";
std::cout << b2.impl->get_int() << "\n";
std::cout << b3.impl->get_int() << "\n";
std::cout << b4.impl->get_int() << "\n";
std::cout << "\n";
std::cout << b1.impl->get_string_ref() << "\n";
std::cout << b2.impl->get_string_ref() << "\n";
std::cout << b3.impl->get_string_ref() << "\n";
std::cout << b4.impl->get_string_ref() << "\n";
std::cout << "\n";
std::cout << b1.impl->get_string_copy() << "\n";
std::cout << b2.impl->get_string_copy() << "\n";
std::cout << b3.impl->get_string_copy() << "\n";
std::cout << b4.impl->get_string_copy() << "\n";
return 0;
}
It was necessary to add an if check in the STRING class to determine whether its safe to request a reference instead of a copy:
Script code:
a = "test";
b = a;
c = 1;
d = "" + c; /* not safe to request reference by standard */
C++ code:
STRING(BaseImpl& that)
{
if (that.is_string())
value = that.get_string_ref();
else
value = that.get_string_copy();
std::cout << "copy constructor called\n";
}
If was hoping there's a way of moving that if check into compile time, rather than run time.