How does one modify the following code to allow template function ask_runUI() to use s_EOF without making s_EOF public?
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
class AskBase {
protected:
std::string m_prompt;
std::string m_answer;
virtual bool validate(std::string a_response) = 0;
public:
AskBase(std::string a_prompt):m_prompt(a_prompt){}
std::string prompt(){return m_prompt;}
std::string answer(){return m_answer;}
static int const s_EOF = -99;
static int const s_BACKUP = -1;
static int const s_OK = 1;
int ask_user();
};
template<typename T> class Ask : public AskBase{
public:
Ask(std::string a_prompt):AskBase(a_prompt){}
bool validate(std::string a_response);
};
template<> bool Ask<std::string>::validate(std::string a_response){return true;}
template<> bool Ask<int>::validate(std::string a_response){int intAnswer;
return (std::stringstream(a_response) >> intAnswer);}
int AskBase::ask_user(){
for(;;){
std::cout << "Enter " << m_prompt;
std::string response;
getline(std::cin, response);
if (std::cin.eof())
return s_EOF;
else if (response == "^")
return s_BACKUP;
else if (validate(response)){
m_answer = response;
return s_OK;
}
}
return s_EOF;
}
template<typename T> int ask_runUI(T& a_ui){
int status = AskBase::s_OK;
for (typename T::iterator ii=a_ui.begin();
status!=AskBase::s_EOF && ii!=a_ui.end();
ii+=((status==AskBase::s_BACKUP)?((ii==a_ui.begin())?0:-1):1)
status = (*ii)->ask_user();
return (status == AskBase::s_OK);
}
int main(){
std::vector<AskBase*> ui;
ui.push_back(new Ask<std::string>("your name: "));
ui.push_back(new Ask<int>("your age: "));
if (ask_runUI(ui))
for (std::vector<AskBase*>::iterator ii=ui.begin(); ii!=ui.end(); ++ii)
std::cout << (*ii)->prompt() << (*ii)->answer() << std::endl;
else
std::cout << "\nEOF\n";
}
If you want a template function to be a friend, you must say so in the class declaration. Change the line that declares the friend function to this:
template <typename T>
friend int ask_runUI(T& a_ui);
Now, if your class is itself a template, things get a lot more complicated. Template friends are not trivial to do correctly. For that, I'll refer you to what C++ FAQ Lite says on the subject.
This worked for me!
class AskBase {
public:
AskBase(){}
template<typename T>
friend int ask_runUI(T& a_ui);
private:
static int const s_EOF = -99;
static int const s_BACKUP = -1;
static int const s_NULL = 0;
static int const s_OK = 1;
};
//int ask_runUI()
template<typename T>
int ask_runUI(T& a_ui)
{
return AskBase::s_NULL;
}
The simplest is probably to replace static int const members with enumeration and not mess with friends:
class AskBase {
public:
enum { Eof = -99, Null = 0, Ok = 1, Backup = -1 };
...
};
Related
I'm just getting started with Object Oriented Programming. I'm trying to access member function of two different classes within a template function. I have restricted access to member functions based on boolean flag isAggregateElement. For some reason, Compiler throws error stating that there is no such member function.
class descriptor{
public:
int getName(){
return -5;
}
};
class aggregate{
public:
int getDescription() {
return 234;
}
int getUnit(){
return 1;
}
};
template <typename T>
void buildObjectInfo(const T& classMemberType, const bool& isDataInterface){
T baseTypeElement = classMemberType;
bool isAggregateElement = !isDataInterface;
if(isAggregateElement){
cout<<baseTypeElement.getUnit()<<endl;
} else {
cout<<baseTypeElement.getName()<<endl; // Error gets resolved if I remove the else construct
}
}
int main()
{
aggregate a;
descriptor d;
buildObjectInfo<aggregate>(a,false);
return 0;
}
What should I do to access getUnit() without deleting boolean condition (or) removing else construct in the template function ?
Both branches must be valid. Suppose you call buildObjectInfo(d,false), what should happen then?
You can use constexpr if to discard the false branch.
Note that the getters should be const methods. The template argument can be deduced from the function parameter and you do not need the bool:
#include <iostream>
#include <type_traits>
struct descriptor{
int getName() const { return -5; }
};
struct aggregate{
int getDescription() const { return 234; }
int getUnit() const { return 1; }
};
template <typename T>
void buildObjectInfo(const T& t){
if constexpr(std::is_same_v<aggregate,T>) {
std::cout << t.getUnit() << '\n';
} else {
std::cout << t.getName() << '\n';
}
}
int main() {
aggregate a;
descriptor d;
buildObjectInfo(a);
buildObjectInfo(d);
}
However, for only 2 different types an overloaded function is much simpler:
#include <iostream>
struct descriptor{
int getName() const { return -5; }
};
struct aggregate{
int getDescription() const { return 234; }
int getUnit() const { return 1; }
};
void buildObjectInfo(const aggregate& t) {
std::cout << t.getUnit() << '\n';
}
void buildObjectInfo(const descriptor& t) {
std::cout << t.getName() << '\n';
}
int main() {
aggregate a;
descriptor d;
buildObjectInfo(a);
buildObjectInfo(d);
}
I got to know that we can also pass template arguments to choose which function should execute. I found them good alternative to function pointers since function pointers has run time cost but template parameters does not. Also, template parameters can be made inline whereas function pointers are not.
Alright then, this is what I wrote to depict my understanding on it. I came close but missing some minor detail somewhere.
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.length()) && (i < str2.length()); ++i) {
if (C::eq(str1[i], str2[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<String<std::string>, Cmp1<std::string> >(s, t);
// compare(s, t);
}
Details of the code:
I have an class String, which take an parameter and create member function of that type.
I have an compare function, which takes two String& arguments. Comparison function is passed to it.
Cmp1 and Cmp2 are two compare functions.
compare<String<std::string>, Cmp1<std::string> >(s, t);
does not get compile here. I tried some other ways to call but in vain.
Looks like you want something like that:
#include <iostream>
#include <string>
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.str.length()) && (i < str2.str.length()); ++i) {
if (C::eq(str1.str[i], str2.str[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
public:
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
public:
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<std::string, Cmp1<char> >(s, t);
// compare(s, t);
}
code
Explanations:
You already have String in definition of compare, you need to just send T which is std::string in your case.
You are trying to go through entire std::string, in compare, so, now your code compiles.
You calling cmp on str[index], that is actually char, so you need to call cmp with char template argument.
Haven't read a book about C++ templates yet so I'm stuck on a problem. I'm using C++14.
How to convert function pointer type to particular string based on type itself?
I have function pointer types:
using FuncType1 = int (*)(double);
using FuncType2 = int (*)(int);
using FuncType3 = int (*)(int);
I would like to write something like this:
class Test {
private:
template<FuncType1> static const std::string func_name = "FuncType1";
template<FuncType2> static const std::string func_name = "FuncType2";
template<FuncType3> static const std::string func_name = "FuncType3";
public:
template<T> std::string GetFuncType() {
return func_name<T>::value;
}
};
I know this doesn't compile but should be enough to show idea. I think it's possible to specialize GetFuncType method but I would prefer to specialize member variable func_name instead (if that's even possible). Also - would FuncType2 and FuncType3 resolve to correct string if code is fixed?
I would prefer to specialize member variable func_name instead (if that's even possible).
So, if I understand correctly, you're looking something as
class Test
{
private:
template <typename> static const std::string func_name;
public:
template <typename T>
std::string GetFuncType () const
{ return func_name<T>; }
};
template <typename> const std::string Test::func_name = "not func";
template<> const std::string Test::func_name<FuncType1> = "FuncType1";
template<> const std::string Test::func_name<FuncType2> = "FuncType2";
template<> const std::string Test::func_name<FuncType3> = "FuncType3";
given that FuncType1, FuncType2 and FuncType3 are different types (not equals as FuncType2 and FuncType3 in you question).
The following is a full compiling example
#include <string>
#include <iostream>
using FuncType1 = int (*)(double);
using FuncType2 = int (*)(int);
using FuncType3 = int (*)(long);
class Test
{
private:
template <typename> static const std::string func_name;
public:
template <typename T>
std::string GetFuncType () const
{ return func_name<T>; }
};
template <typename> const std::string Test::func_name = "not func";
template<> const std::string Test::func_name<FuncType1> = "FuncType1";
template<> const std::string Test::func_name<FuncType2> = "FuncType2";
template<> const std::string Test::func_name<FuncType3> = "FuncType3";
int main ()
{
std::cout << Test{}.GetFuncType<int>() << std::endl;
std::cout << Test{}.GetFuncType<FuncType1>() << std::endl;
std::cout << Test{}.GetFuncType<FuncType2>() << std::endl;
std::cout << Test{}.GetFuncType<FuncType3>() << std::endl;
}
If you want that Test{}.GetFuncType<int>() gives a compilation error, you can initialize func_name only for requested specializations
// template <typename> const std::string Test::func_name = "not func";
template<> const std::string Test::func_name<FuncType1> = "FuncType1";
template<> const std::string Test::func_name<FuncType2> = "FuncType2";
template<> const std::string Test::func_name<FuncType3> = "FuncType3";
// ...
std::cout << Test{}.GetFuncType<int>() << std::endl; // compilation error!
One way:
template<class T> constexpr char const* get_name() = delete;
using FuncType1 = int (*)(double);
using FuncType2 = int (*)(int);
template<> constexpr char const* get_name<FuncType1>() { return "FuncType1"; }
template<> constexpr char const* get_name<FuncType2>() { return "FuncType2"; }
int main() {
std::cout << get_name<FuncType1>() << '\n';
std::cout << get_name<FuncType2>() << '\n';
}
In C++ you can use virtual methods to have following code work as you expect:
#include <iostream>
#include <string>
class BaseClass {
public:
virtual std::string class_name() const { return "Base Class"; }
};
class FirstClass : public BaseClass {
int value = 1;
public:
std::string class_name() const { return "FirstClass"; }
};
class SecondClass : public BaseClass {
long long value = -1;
public:
std::string class_name() const { return "SecondClass"; }
};
int main() {
const int array_size = 5;
const bool in_first_mode = true;
void *data;
int sample_size;
if (in_first_mode) {
data = new FirstClass[array_size];
sample_size = sizeof(FirstClass);
} else {
data = new SecondClass[array_size];
sample_size = sizeof(SecondClass);
}
// this is class-independent code
for (int index = 0; index < array_size; ++index) {
BaseClass *pointer = static_cast<BaseClass*>(data + index * sample_size);
std::cout << pointer->class_name() << std::endl;
}
return 0;
}
This will work correctly for both in_first_mode = true and in_first_mode = false.
So, basically, when you want to write code that works for both classes you can just use pointer to the BaseClass.
But what if you already given data buffer, filled with data of type TypeOne, TypeTwo, TypeThree or TypeFour, and in runtime you know that type, which stored in int type. Problem is that TypeOne, TypeTwo, TypeThree and TypeFour have not inherited from one base class. In my case, actually, they are structs from 3rd party library, which is already compiled C-compatible library, so I can not modify it. I want to get something like pointer from the example above, but problem arises with identifying what C++ type should have this pointer.
It there a more elegant type-casting alternative to making C++ class wrappers to these four types (which gives something similar to the example above), and to making pointer be void * and necessity of
if (type == 1) {
TypeOne *type_one_pointer = static_cast<TypeOne*>(pointer);
// do something
} else if (type == 2) {
/* ... */
}
every time I use pointer?
If the classes are unrelated, you can store them in a std::variant (or use Boost.Variant if your compiler is not C++17 compliant) and access the value with a visitor. This is more flexible than templates, as it allows you to include types with a different interface in the variant type.
For example (I did not compile this code):
#include <iostream>
#include <string>
#include <variant>
#include <vector>
struct TypeOne {
std::string class_name() const { return "Type one"; }
};
struct TypeTwo {
int value = 1;
std::string class_name() const { return "Type two"; }
};
struct TypeThree {
long long value = -1;
// note the different function signature
static std::string class_name() { return "Type three"; }
};
struct TypeFour {
std::string getMyClassName() const { return "Type four"; }
};
struct Visitor {
template <class T>
void operator ()(T&& value) const {
std::cout << value.class_name() << std::endl;
}
// special case
void operator ()(const TypeFour& value) const {
std::cout << value.getMyClassName() << std::endl;
}
};
int main() {
typedef std::variant<TypeOne, TypeTwo, TypeThree, TypeFour> Variant;
std::vector<Variant> values;
values.emplace_back(TypeOne{});
values.emplace_back(TypeTwo{});
values.emplace_back(TypeThree{});
values.emplace_back(TypeFour{});
for (const auto& var : values) {
std::visit(Visitor{}, var);
}
}
Thanks to #ForEveR, I find the solution. I need to use templates.
It means that if in the example above FirstClass and SecondClass would have no BaseClass one can do so:
#include <iostream>
#include <string>
class FirstClass {
int value = 1;
public:
std::string class_name() const { return "FirstClass"; }
};
class SecondClass {
long long value = -1;
public:
std::string class_name() const { return "SecondClass"; }
};
template <typename T>
void do_my_stuff(void* void_pointer) {
T *pointer = static_cast<T*>(void_pointer);
std::cout << pointer->class_name() << std::endl;
}
int main() {
const int array_size = 5;
const bool in_first_mode = true;
void *data;
int sample_size;
if (in_first_mode) {
data = new FirstClass[array_size];
sample_size = sizeof(FirstClass);
} else {
data = new SecondClass[array_size];
sample_size = sizeof(SecondClass);
}
for (int index = 0; index < array_size; ++index) {
if (in_first_mode) {
do_my_stuff<FirstClass>(data + index * sample_size);
} else {
do_my_stuff<SecondClass>(data + index * sample_size);
}
}
return 0;
}
As far as I know, this seems to be impossible in a straightforward way. Making the member const makes it const for everyone. I would like to have a read-only property, but would like to avoid the typical "getter". I'd like const public, mutable private. Is this at all possible in C++?
Currently all I can think of is some trickery with templates and friend. I'm investigating this now.
Might seem like a stupid question, but I have been surprised by answers here before.
A possible solution can be based on an inner class of which the outer one is a friend, like the following one:
struct S {
template<typename T>
class Prop {
friend struct S;
T t;
void operator=(T val) { t = val; }
public:
operator const T &() const { return t; }
};
void f() {
prop = 42;
}
Prop<int> prop;
};
int main() {
S s;
int i = s.prop;
//s.prop = 0;
s.f();
return i, 0;
}
As shown in the example, the class S can modify the property from within its member functions (see S::f). On the other side, the property cannot be modified in any other way but still read by means of the given operator that returns a const reference to the actual variable.
There seems to be another, more obvious solution: use a public const reference member, pointing to the private, mutable, member. live code here.
#include <iostream>
struct S {
private:
int member;
public:
const int& prop;
S() : member{42}, prop{member} {}
S(const S& s) : member{s.member}, prop{member} {}
S(S&& s) : member(s.member), prop{member} {}
S& operator=(const S& s) { member = s.member; return *this; }
S& operator=(S&& s) { member = s.member; return *this; }
void f() { member = 32; }
};
int main() {
using namespace std;
S s;
int i = s.prop;
cout << i << endl;
cout << s.prop << endl;
S s2{s};
// s.prop = 32; // ERROR: does not compile
s.f();
cout << s.prop << endl;
cout << s2.prop << endl;
s2.f();
S s3 = move(s2);
cout << s3.prop << endl;
S s4;
cout << s4.prop << endl;
s4 = s3;
cout << s4.prop << endl;
s4 = S{};
cout << s4.prop << endl;
}
I like #skypjack's answer, but would have written it somehow like this:
#include <iostream>
template <class Parent, class Value> class ROMember {
friend Parent;
Value v_;
inline ROMember(Value const &v) : v_{v} {}
inline ROMember(Value &&v) : v_{std::move(v)} {}
inline Value &operator=(Value const &v) {
v_ = v;
return v_;
}
inline Value &operator=(Value &&v) {
v_ = std::move(v);
return v_;
}
inline operator Value& () & {
return v_;
}
inline operator Value const & () const & {
return v_;
}
inline operator Value&& () && {
return std::move(v_);
}
public:
inline Value const &operator()() const { return v_; }
};
class S {
template <class T> using member_t = ROMember<S, T>;
public:
member_t<int> val = 0;
void f() { val = 1; }
};
int main() {
S s;
std::cout << s.val() << "\n";
s.f();
std::cout << s.val() << "\n";
return 0;
}
Some enable_ifs are missing to really be generic to the core, but the spirit is to make it re-usable and to keep the calls looking like getters.
This is indeed a trickery with friend.
You can use curiously recurring template pattern and friend the super class from within a property class like so:
#include <utility>
#include <cassert>
template<typename Super, typename T>
class property {
friend Super;
protected:
T& operator=(const T& val)
{ value = val; return value; }
T& operator=(T&& val)
{ value = val; return value; }
operator T && () &&
{ return std::move(value); }
public:
operator T const& () const&
{ return value; }
private:
T value;
};
struct wrap {
wrap() {
// Assign OK
prop1 = 5; // This is legal since we are friends
prop2 = 10;
prop3 = 15;
// Move OK
prop2 = std::move(prop1);
assert(prop1 == 5 && prop2 == 5);
// Swap OK
std::swap(prop2, prop3);
assert(prop2 == 15 && prop3 == 5);
}
property<wrap, int> prop1;
property<wrap, int> prop2;
property<wrap, int> prop3;
};
int foo() {
wrap w{};
w.prop1 = 5; // This is illegal since operator= is protected
return w.prop1; // But this is perfectly legal
}