Meta Mixin.. is that even a thing? (Template Meta-Programming)
I want to present a "pattern of mixin based structure"(is this even a term?) but not quite sure if it would hold up in "some situation".
Basic idea is to generate "type using template class" that multiply inherit mixins. So the type declaration would look like: typedef BaseType<Mixin1, Mixin2, MixinN> Type1;
Some accomplishments by the approach:
Type1
's special feature like operator overloads and Constructor overloads are always available.- Explicit type casting overhead is abstracted away by
BaseType
. - C++ multiple implicit conversion barrier is not a problem.
Usual template mixin approach form here looks like: template<class Base> class Printing : public Base {...}
. Main drawback for me with this approach:
- It is necessary to explicitly cast
Printing
toBase
to use some ofBase
's special features, Or have to provide those overloads explicitly (I know it would just be a matter of one line of codes). But in some situation it would be irritating.
That is why I have come up with the idea to generate the base.
Please take a look at the implementation ("some situation"):
#include <iostream>
#include <functional>
#ifdef QT_CORE_LIB
#include <QString>
#endif
template<template<class> class... mixin_t>
class StringType : public mixin_t<StringType<mixin_t...>>...
{
std::string _value;
public:
StringType() : _value("") {}
StringType(const StringType &other) = default; // Copy
StringType(StringType &&other) = default; // Move
#ifdef QT_CORE_LIB
StringType(const QString &value) { this->_value = value.toStdString(); }
#endif
StringType(const std::string &value) { _value = value; }
StringType(const char *value) { _value = value; }
template<template<class> class T>
StringType(const StringType<T> &value)
{
_value = static_cast<const std::string &>(value);
}
StringType &operator=(const StringType &rhs) = default; // copy assign
StringType &operator=(StringType &&rhs) = default; // Move assign
#ifdef QT_CORE_LIB
operator QString() const { return QString::fromStdString(_value);}
#endif
operator std::string() const { return _value; }
operator const char *() const{ return _value.c_str(); }
};
template<class this_t> struct _empty_mixn {};
template<class this_t> struct ToStringMixin
{
this_t toString() const { return *static_cast<const this_t *>(this); }
};
template<class this_t> struct StringPrinterMixin
{
void print() const
{
std::cout << "From the printer: " << *static_cast<const this_t *>(this);
}
};
typedef StringType<_empty_mixn> String;
typedef StringType<ToStringMixin> Message;
typedef StringType<ToStringMixin, StringPrinterMixin> PrinterAttachedString;
int main()
{
Message msg1(String("msg1n"));
std::cout << msg1;
std::cout << "toString() : " << msg1.toString();
Message msg2 = String("msg2n");
std::cout << msg2;
std::cout << "toString() : " << msg2.toString();
Message msg3(std::string("msg3n"));
std::cout << msg3;
std::cout << "toString() : " << msg3.toString();
Message msg4 = std::string("msg4n");
std::cout << msg4;
std::cout << "toString() : " << msg4.toString();
Message msg5("msg5n");
std::cout << msg5;
std::cout << "toString() : " << msg5.toString();
Message msg6 = "msg6n";
std::cout << msg6;
std::cout << "toString() : " << msg6.toString();
std::cout << "n---------------------nn";
PrinterAttachedString str1(String("str1n"));
std::cout << str1;
std::cout << "toString() : " << str1.toString();
str1.print();
PrinterAttachedString str2 = String("str2n");
std::cout << str2;
std::cout << "toString() : " << str2.toString();
str2.print();
PrinterAttachedString str3(std::string("str3n"));
std::cout << str3;
std::cout << "toString() : " << str3.toString();
str3.print();
PrinterAttachedString str4 = std::string("str4n");
std::cout << str4;
std::cout << "toString() : " << str4.toString();
str4.print();
PrinterAttachedString str5("str5n");
std::cout << str5;
std::cout << "toString() : " << str5.toString();
str5.print();
PrinterAttachedString str6 = "str6n";
std::cout << str6;
std::cout << "toString() : " << str6.toString();
str6.print();
return 0;
}
So, my questions:
Would it be practical use this in a situation where operator overloading/implicit casting feature necessary?Does it seem, there would be a necessity of virtual inheritance?Are there any other implementation like this (My search was a failure)?Finally, is there a thing called "meta mixin" that would provide a type's special features?
Edit: In response to Phil1970's answer:
I am going to start with the answer to the question 3.
- This approach leads to class proliferation: I totally agree. One big drawback I have to admit.
- Increases coupling. Not sure how it increases coupling. *1
- The rests marked there, I believe is not applicable due to the fact that
StringType
is quitefinal
. AndStringType
does not know or about mixed class for real. *1
Now for the answer to the question no 1.
- It is usually best to avoid implicit conversion.
- The rests to me is ok as long as it is
final
. *2
With previous question gone (huge thanks to Phil) arose new questions.
- *1: It is just one header-only,
StringStyle
does not depend on mixins and I see no reason to be so. And certainly this it can use private header if somehow becomes necessary. Then how it enforcing coupling? - *2: Just looking for opinions or to get me corrected.
Thanks a lot.
c++ c++11 mixins template-meta-programming crtp
|
show 8 more comments
I want to present a "pattern of mixin based structure"(is this even a term?) but not quite sure if it would hold up in "some situation".
Basic idea is to generate "type using template class" that multiply inherit mixins. So the type declaration would look like: typedef BaseType<Mixin1, Mixin2, MixinN> Type1;
Some accomplishments by the approach:
Type1
's special feature like operator overloads and Constructor overloads are always available.- Explicit type casting overhead is abstracted away by
BaseType
. - C++ multiple implicit conversion barrier is not a problem.
Usual template mixin approach form here looks like: template<class Base> class Printing : public Base {...}
. Main drawback for me with this approach:
- It is necessary to explicitly cast
Printing
toBase
to use some ofBase
's special features, Or have to provide those overloads explicitly (I know it would just be a matter of one line of codes). But in some situation it would be irritating.
That is why I have come up with the idea to generate the base.
Please take a look at the implementation ("some situation"):
#include <iostream>
#include <functional>
#ifdef QT_CORE_LIB
#include <QString>
#endif
template<template<class> class... mixin_t>
class StringType : public mixin_t<StringType<mixin_t...>>...
{
std::string _value;
public:
StringType() : _value("") {}
StringType(const StringType &other) = default; // Copy
StringType(StringType &&other) = default; // Move
#ifdef QT_CORE_LIB
StringType(const QString &value) { this->_value = value.toStdString(); }
#endif
StringType(const std::string &value) { _value = value; }
StringType(const char *value) { _value = value; }
template<template<class> class T>
StringType(const StringType<T> &value)
{
_value = static_cast<const std::string &>(value);
}
StringType &operator=(const StringType &rhs) = default; // copy assign
StringType &operator=(StringType &&rhs) = default; // Move assign
#ifdef QT_CORE_LIB
operator QString() const { return QString::fromStdString(_value);}
#endif
operator std::string() const { return _value; }
operator const char *() const{ return _value.c_str(); }
};
template<class this_t> struct _empty_mixn {};
template<class this_t> struct ToStringMixin
{
this_t toString() const { return *static_cast<const this_t *>(this); }
};
template<class this_t> struct StringPrinterMixin
{
void print() const
{
std::cout << "From the printer: " << *static_cast<const this_t *>(this);
}
};
typedef StringType<_empty_mixn> String;
typedef StringType<ToStringMixin> Message;
typedef StringType<ToStringMixin, StringPrinterMixin> PrinterAttachedString;
int main()
{
Message msg1(String("msg1n"));
std::cout << msg1;
std::cout << "toString() : " << msg1.toString();
Message msg2 = String("msg2n");
std::cout << msg2;
std::cout << "toString() : " << msg2.toString();
Message msg3(std::string("msg3n"));
std::cout << msg3;
std::cout << "toString() : " << msg3.toString();
Message msg4 = std::string("msg4n");
std::cout << msg4;
std::cout << "toString() : " << msg4.toString();
Message msg5("msg5n");
std::cout << msg5;
std::cout << "toString() : " << msg5.toString();
Message msg6 = "msg6n";
std::cout << msg6;
std::cout << "toString() : " << msg6.toString();
std::cout << "n---------------------nn";
PrinterAttachedString str1(String("str1n"));
std::cout << str1;
std::cout << "toString() : " << str1.toString();
str1.print();
PrinterAttachedString str2 = String("str2n");
std::cout << str2;
std::cout << "toString() : " << str2.toString();
str2.print();
PrinterAttachedString str3(std::string("str3n"));
std::cout << str3;
std::cout << "toString() : " << str3.toString();
str3.print();
PrinterAttachedString str4 = std::string("str4n");
std::cout << str4;
std::cout << "toString() : " << str4.toString();
str4.print();
PrinterAttachedString str5("str5n");
std::cout << str5;
std::cout << "toString() : " << str5.toString();
str5.print();
PrinterAttachedString str6 = "str6n";
std::cout << str6;
std::cout << "toString() : " << str6.toString();
str6.print();
return 0;
}
So, my questions:
Would it be practical use this in a situation where operator overloading/implicit casting feature necessary?Does it seem, there would be a necessity of virtual inheritance?Are there any other implementation like this (My search was a failure)?Finally, is there a thing called "meta mixin" that would provide a type's special features?
Edit: In response to Phil1970's answer:
I am going to start with the answer to the question 3.
- This approach leads to class proliferation: I totally agree. One big drawback I have to admit.
- Increases coupling. Not sure how it increases coupling. *1
- The rests marked there, I believe is not applicable due to the fact that
StringType
is quitefinal
. AndStringType
does not know or about mixed class for real. *1
Now for the answer to the question no 1.
- It is usually best to avoid implicit conversion.
- The rests to me is ok as long as it is
final
. *2
With previous question gone (huge thanks to Phil) arose new questions.
- *1: It is just one header-only,
StringStyle
does not depend on mixins and I see no reason to be so. And certainly this it can use private header if somehow becomes necessary. Then how it enforcing coupling? - *2: Just looking for opinions or to get me corrected.
Thanks a lot.
c++ c++11 mixins template-meta-programming crtp
I would say it is the wrong approach… Use a namespace with free function or if the code is more complex, use an helper class. For example:namespace Printer { void print(const string &s) { std::cout << "From the printer: " << s; } }
– Phil1970
Nov 16 '18 at 1:18
@Phil1970print()
ortoString()
is rally not my concern. Please see in my code that operator overloading (assignment & casting) and constructor conversion is the main feature here since it wraps different string implementation. Will be very glad if reconsider to check again my approach. Thanks.
– Shabbir Ahmed
Nov 16 '18 at 1:41
1
Well your implementation forces UB. So that is bad.
– Yakk - Adam Nevraumont
Nov 16 '18 at 1:58
Fix;mixin_t<StringType<mixin_t...>>...
– Yakk - Adam Nevraumont
Nov 16 '18 at 2:09
1
@shabb CRTP is unsafe and unchecked.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:04
|
show 8 more comments
I want to present a "pattern of mixin based structure"(is this even a term?) but not quite sure if it would hold up in "some situation".
Basic idea is to generate "type using template class" that multiply inherit mixins. So the type declaration would look like: typedef BaseType<Mixin1, Mixin2, MixinN> Type1;
Some accomplishments by the approach:
Type1
's special feature like operator overloads and Constructor overloads are always available.- Explicit type casting overhead is abstracted away by
BaseType
. - C++ multiple implicit conversion barrier is not a problem.
Usual template mixin approach form here looks like: template<class Base> class Printing : public Base {...}
. Main drawback for me with this approach:
- It is necessary to explicitly cast
Printing
toBase
to use some ofBase
's special features, Or have to provide those overloads explicitly (I know it would just be a matter of one line of codes). But in some situation it would be irritating.
That is why I have come up with the idea to generate the base.
Please take a look at the implementation ("some situation"):
#include <iostream>
#include <functional>
#ifdef QT_CORE_LIB
#include <QString>
#endif
template<template<class> class... mixin_t>
class StringType : public mixin_t<StringType<mixin_t...>>...
{
std::string _value;
public:
StringType() : _value("") {}
StringType(const StringType &other) = default; // Copy
StringType(StringType &&other) = default; // Move
#ifdef QT_CORE_LIB
StringType(const QString &value) { this->_value = value.toStdString(); }
#endif
StringType(const std::string &value) { _value = value; }
StringType(const char *value) { _value = value; }
template<template<class> class T>
StringType(const StringType<T> &value)
{
_value = static_cast<const std::string &>(value);
}
StringType &operator=(const StringType &rhs) = default; // copy assign
StringType &operator=(StringType &&rhs) = default; // Move assign
#ifdef QT_CORE_LIB
operator QString() const { return QString::fromStdString(_value);}
#endif
operator std::string() const { return _value; }
operator const char *() const{ return _value.c_str(); }
};
template<class this_t> struct _empty_mixn {};
template<class this_t> struct ToStringMixin
{
this_t toString() const { return *static_cast<const this_t *>(this); }
};
template<class this_t> struct StringPrinterMixin
{
void print() const
{
std::cout << "From the printer: " << *static_cast<const this_t *>(this);
}
};
typedef StringType<_empty_mixn> String;
typedef StringType<ToStringMixin> Message;
typedef StringType<ToStringMixin, StringPrinterMixin> PrinterAttachedString;
int main()
{
Message msg1(String("msg1n"));
std::cout << msg1;
std::cout << "toString() : " << msg1.toString();
Message msg2 = String("msg2n");
std::cout << msg2;
std::cout << "toString() : " << msg2.toString();
Message msg3(std::string("msg3n"));
std::cout << msg3;
std::cout << "toString() : " << msg3.toString();
Message msg4 = std::string("msg4n");
std::cout << msg4;
std::cout << "toString() : " << msg4.toString();
Message msg5("msg5n");
std::cout << msg5;
std::cout << "toString() : " << msg5.toString();
Message msg6 = "msg6n";
std::cout << msg6;
std::cout << "toString() : " << msg6.toString();
std::cout << "n---------------------nn";
PrinterAttachedString str1(String("str1n"));
std::cout << str1;
std::cout << "toString() : " << str1.toString();
str1.print();
PrinterAttachedString str2 = String("str2n");
std::cout << str2;
std::cout << "toString() : " << str2.toString();
str2.print();
PrinterAttachedString str3(std::string("str3n"));
std::cout << str3;
std::cout << "toString() : " << str3.toString();
str3.print();
PrinterAttachedString str4 = std::string("str4n");
std::cout << str4;
std::cout << "toString() : " << str4.toString();
str4.print();
PrinterAttachedString str5("str5n");
std::cout << str5;
std::cout << "toString() : " << str5.toString();
str5.print();
PrinterAttachedString str6 = "str6n";
std::cout << str6;
std::cout << "toString() : " << str6.toString();
str6.print();
return 0;
}
So, my questions:
Would it be practical use this in a situation where operator overloading/implicit casting feature necessary?Does it seem, there would be a necessity of virtual inheritance?Are there any other implementation like this (My search was a failure)?Finally, is there a thing called "meta mixin" that would provide a type's special features?
Edit: In response to Phil1970's answer:
I am going to start with the answer to the question 3.
- This approach leads to class proliferation: I totally agree. One big drawback I have to admit.
- Increases coupling. Not sure how it increases coupling. *1
- The rests marked there, I believe is not applicable due to the fact that
StringType
is quitefinal
. AndStringType
does not know or about mixed class for real. *1
Now for the answer to the question no 1.
- It is usually best to avoid implicit conversion.
- The rests to me is ok as long as it is
final
. *2
With previous question gone (huge thanks to Phil) arose new questions.
- *1: It is just one header-only,
StringStyle
does not depend on mixins and I see no reason to be so. And certainly this it can use private header if somehow becomes necessary. Then how it enforcing coupling? - *2: Just looking for opinions or to get me corrected.
Thanks a lot.
c++ c++11 mixins template-meta-programming crtp
I want to present a "pattern of mixin based structure"(is this even a term?) but not quite sure if it would hold up in "some situation".
Basic idea is to generate "type using template class" that multiply inherit mixins. So the type declaration would look like: typedef BaseType<Mixin1, Mixin2, MixinN> Type1;
Some accomplishments by the approach:
Type1
's special feature like operator overloads and Constructor overloads are always available.- Explicit type casting overhead is abstracted away by
BaseType
. - C++ multiple implicit conversion barrier is not a problem.
Usual template mixin approach form here looks like: template<class Base> class Printing : public Base {...}
. Main drawback for me with this approach:
- It is necessary to explicitly cast
Printing
toBase
to use some ofBase
's special features, Or have to provide those overloads explicitly (I know it would just be a matter of one line of codes). But in some situation it would be irritating.
That is why I have come up with the idea to generate the base.
Please take a look at the implementation ("some situation"):
#include <iostream>
#include <functional>
#ifdef QT_CORE_LIB
#include <QString>
#endif
template<template<class> class... mixin_t>
class StringType : public mixin_t<StringType<mixin_t...>>...
{
std::string _value;
public:
StringType() : _value("") {}
StringType(const StringType &other) = default; // Copy
StringType(StringType &&other) = default; // Move
#ifdef QT_CORE_LIB
StringType(const QString &value) { this->_value = value.toStdString(); }
#endif
StringType(const std::string &value) { _value = value; }
StringType(const char *value) { _value = value; }
template<template<class> class T>
StringType(const StringType<T> &value)
{
_value = static_cast<const std::string &>(value);
}
StringType &operator=(const StringType &rhs) = default; // copy assign
StringType &operator=(StringType &&rhs) = default; // Move assign
#ifdef QT_CORE_LIB
operator QString() const { return QString::fromStdString(_value);}
#endif
operator std::string() const { return _value; }
operator const char *() const{ return _value.c_str(); }
};
template<class this_t> struct _empty_mixn {};
template<class this_t> struct ToStringMixin
{
this_t toString() const { return *static_cast<const this_t *>(this); }
};
template<class this_t> struct StringPrinterMixin
{
void print() const
{
std::cout << "From the printer: " << *static_cast<const this_t *>(this);
}
};
typedef StringType<_empty_mixn> String;
typedef StringType<ToStringMixin> Message;
typedef StringType<ToStringMixin, StringPrinterMixin> PrinterAttachedString;
int main()
{
Message msg1(String("msg1n"));
std::cout << msg1;
std::cout << "toString() : " << msg1.toString();
Message msg2 = String("msg2n");
std::cout << msg2;
std::cout << "toString() : " << msg2.toString();
Message msg3(std::string("msg3n"));
std::cout << msg3;
std::cout << "toString() : " << msg3.toString();
Message msg4 = std::string("msg4n");
std::cout << msg4;
std::cout << "toString() : " << msg4.toString();
Message msg5("msg5n");
std::cout << msg5;
std::cout << "toString() : " << msg5.toString();
Message msg6 = "msg6n";
std::cout << msg6;
std::cout << "toString() : " << msg6.toString();
std::cout << "n---------------------nn";
PrinterAttachedString str1(String("str1n"));
std::cout << str1;
std::cout << "toString() : " << str1.toString();
str1.print();
PrinterAttachedString str2 = String("str2n");
std::cout << str2;
std::cout << "toString() : " << str2.toString();
str2.print();
PrinterAttachedString str3(std::string("str3n"));
std::cout << str3;
std::cout << "toString() : " << str3.toString();
str3.print();
PrinterAttachedString str4 = std::string("str4n");
std::cout << str4;
std::cout << "toString() : " << str4.toString();
str4.print();
PrinterAttachedString str5("str5n");
std::cout << str5;
std::cout << "toString() : " << str5.toString();
str5.print();
PrinterAttachedString str6 = "str6n";
std::cout << str6;
std::cout << "toString() : " << str6.toString();
str6.print();
return 0;
}
So, my questions:
Would it be practical use this in a situation where operator overloading/implicit casting feature necessary?Does it seem, there would be a necessity of virtual inheritance?Are there any other implementation like this (My search was a failure)?Finally, is there a thing called "meta mixin" that would provide a type's special features?
Edit: In response to Phil1970's answer:
I am going to start with the answer to the question 3.
- This approach leads to class proliferation: I totally agree. One big drawback I have to admit.
- Increases coupling. Not sure how it increases coupling. *1
- The rests marked there, I believe is not applicable due to the fact that
StringType
is quitefinal
. AndStringType
does not know or about mixed class for real. *1
Now for the answer to the question no 1.
- It is usually best to avoid implicit conversion.
- The rests to me is ok as long as it is
final
. *2
With previous question gone (huge thanks to Phil) arose new questions.
- *1: It is just one header-only,
StringStyle
does not depend on mixins and I see no reason to be so. And certainly this it can use private header if somehow becomes necessary. Then how it enforcing coupling? - *2: Just looking for opinions or to get me corrected.
Thanks a lot.
c++ c++11 mixins template-meta-programming crtp
c++ c++11 mixins template-meta-programming crtp
edited Nov 16 '18 at 7:04
Shabbir Ahmed
asked Nov 16 '18 at 0:43
Shabbir AhmedShabbir Ahmed
62
62
I would say it is the wrong approach… Use a namespace with free function or if the code is more complex, use an helper class. For example:namespace Printer { void print(const string &s) { std::cout << "From the printer: " << s; } }
– Phil1970
Nov 16 '18 at 1:18
@Phil1970print()
ortoString()
is rally not my concern. Please see in my code that operator overloading (assignment & casting) and constructor conversion is the main feature here since it wraps different string implementation. Will be very glad if reconsider to check again my approach. Thanks.
– Shabbir Ahmed
Nov 16 '18 at 1:41
1
Well your implementation forces UB. So that is bad.
– Yakk - Adam Nevraumont
Nov 16 '18 at 1:58
Fix;mixin_t<StringType<mixin_t...>>...
– Yakk - Adam Nevraumont
Nov 16 '18 at 2:09
1
@shabb CRTP is unsafe and unchecked.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:04
|
show 8 more comments
I would say it is the wrong approach… Use a namespace with free function or if the code is more complex, use an helper class. For example:namespace Printer { void print(const string &s) { std::cout << "From the printer: " << s; } }
– Phil1970
Nov 16 '18 at 1:18
@Phil1970print()
ortoString()
is rally not my concern. Please see in my code that operator overloading (assignment & casting) and constructor conversion is the main feature here since it wraps different string implementation. Will be very glad if reconsider to check again my approach. Thanks.
– Shabbir Ahmed
Nov 16 '18 at 1:41
1
Well your implementation forces UB. So that is bad.
– Yakk - Adam Nevraumont
Nov 16 '18 at 1:58
Fix;mixin_t<StringType<mixin_t...>>...
– Yakk - Adam Nevraumont
Nov 16 '18 at 2:09
1
@shabb CRTP is unsafe and unchecked.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:04
I would say it is the wrong approach… Use a namespace with free function or if the code is more complex, use an helper class. For example:
namespace Printer { void print(const string &s) { std::cout << "From the printer: " << s; } }
– Phil1970
Nov 16 '18 at 1:18
I would say it is the wrong approach… Use a namespace with free function or if the code is more complex, use an helper class. For example:
namespace Printer { void print(const string &s) { std::cout << "From the printer: " << s; } }
– Phil1970
Nov 16 '18 at 1:18
@Phil1970
print()
or toString()
is rally not my concern. Please see in my code that operator overloading (assignment & casting) and constructor conversion is the main feature here since it wraps different string implementation. Will be very glad if reconsider to check again my approach. Thanks.– Shabbir Ahmed
Nov 16 '18 at 1:41
@Phil1970
print()
or toString()
is rally not my concern. Please see in my code that operator overloading (assignment & casting) and constructor conversion is the main feature here since it wraps different string implementation. Will be very glad if reconsider to check again my approach. Thanks.– Shabbir Ahmed
Nov 16 '18 at 1:41
1
1
Well your implementation forces UB. So that is bad.
– Yakk - Adam Nevraumont
Nov 16 '18 at 1:58
Well your implementation forces UB. So that is bad.
– Yakk - Adam Nevraumont
Nov 16 '18 at 1:58
Fix;
mixin_t<StringType<mixin_t...>>...
– Yakk - Adam Nevraumont
Nov 16 '18 at 2:09
Fix;
mixin_t<StringType<mixin_t...>>...
– Yakk - Adam Nevraumont
Nov 16 '18 at 2:09
1
1
@shabb CRTP is unsafe and unchecked.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:04
@shabb CRTP is unsafe and unchecked.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:04
|
show 8 more comments
1 Answer
1
active
oldest
votes
For your question:
- It is usually best to avoid implicit conversion. Also you won't be able to reuse
std::string
operators like +, += with that kind of approach without adding a lot one line function. The wrapper class bring you nothing except adding more conversions as you would then use you new string type and with the mixin approach, this is even worst as you need to also convert between your own types. - Why would you use virtual inheritance? Do you really want to derive from multiple classes that have a common base and that have their own data.
- As this is a bad design, you probably won't find many people doing it. Your design increase coupling, lead to class proliferation, increase type conversions and make maintenance harder among other things.
- I believe, there is no such thing.
For simple functions like those above, the preferred approach would be to define a namespace (or many if you have a lot of functions that could somehow be categorized like maybe file name manipulation) and then have free functions inside it.
By using a namespace, you have a few advantages:
- If you call a lot of functions, you can always add an using statement inside your function or source file (never in a header file).
- Auto suggestion will work well to find those function.
If some of the original mixin maintain state, then you should do an helper class. This could be the case for a class like an HTML builder that might have functions like AddTag, Add Attribute, AddEncodedUrl etc that could be used to create an HTML document.
One big advantage of this approach is that coupling is much looser than in your design. For example, a file pair (header and source) would contains all functions used for the Printer. If you need that, you don't have to create a new class that use some combination of mixin.
One big problem with your approach, is that with time you will have a lot of different StringType<…>
If you have 5 mixins that could be used, you have 2^5 = 32 classes. At that point, it is almost sure that you will often need the mixin you didn't include and then you have cascading change if the call it deep. And if you use template everywhere then you will have compilation slowdown and probably some code bloat.
Implicit conversion is also considered to be best avoid in most cases by most experts. If you have multiple conversion from and to many classes, at some point you will have unexpected conversion or ambiguities. Making some conversion explicit can limit the problem. Usually is it best to use explicite conversion as it was done by experts in std::string
. You have to call member function c_str()
if you want a C style string.
For example, since your StringType
class define conversion to both const char *
and QString
, then if you have a method that accept both (maybe an Append function), then you have a conflict.
If you really want conversion, then use named method instead (for ex. AsQString()
, c_str()
, tostdstring()
...). It help ensure that all conversion are intended. It make it easier to find them and it is certainly better that explicit cast like you have done in a few place in your code. While static_cast
and other casts are sometime useful, then can also hide some problem when code is refactored as in some case, the cast might compile while not being correct. This would be the case if you cast to a derived class and at some point decide to change the derived class for something else and forget to update some casts.
You should select the most appropriate string for your application and do conversion when required. In a large application, you might use one type for the UI (ex. CString or QString) while using standard string in librairies that are shared across platforms or with third party library. Some time those libraries have their own string class too. Your selection should try minimize useless conversions.
I can't thank you enough for your precious time. If you feel like to spend more time please check my updated questions. Have a nice day.
– Shabbir Ahmed
Nov 16 '18 at 7:06
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53329850%2fmeta-mixin-is-that-even-a-thing-template-meta-programming%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
For your question:
- It is usually best to avoid implicit conversion. Also you won't be able to reuse
std::string
operators like +, += with that kind of approach without adding a lot one line function. The wrapper class bring you nothing except adding more conversions as you would then use you new string type and with the mixin approach, this is even worst as you need to also convert between your own types. - Why would you use virtual inheritance? Do you really want to derive from multiple classes that have a common base and that have their own data.
- As this is a bad design, you probably won't find many people doing it. Your design increase coupling, lead to class proliferation, increase type conversions and make maintenance harder among other things.
- I believe, there is no such thing.
For simple functions like those above, the preferred approach would be to define a namespace (or many if you have a lot of functions that could somehow be categorized like maybe file name manipulation) and then have free functions inside it.
By using a namespace, you have a few advantages:
- If you call a lot of functions, you can always add an using statement inside your function or source file (never in a header file).
- Auto suggestion will work well to find those function.
If some of the original mixin maintain state, then you should do an helper class. This could be the case for a class like an HTML builder that might have functions like AddTag, Add Attribute, AddEncodedUrl etc that could be used to create an HTML document.
One big advantage of this approach is that coupling is much looser than in your design. For example, a file pair (header and source) would contains all functions used for the Printer. If you need that, you don't have to create a new class that use some combination of mixin.
One big problem with your approach, is that with time you will have a lot of different StringType<…>
If you have 5 mixins that could be used, you have 2^5 = 32 classes. At that point, it is almost sure that you will often need the mixin you didn't include and then you have cascading change if the call it deep. And if you use template everywhere then you will have compilation slowdown and probably some code bloat.
Implicit conversion is also considered to be best avoid in most cases by most experts. If you have multiple conversion from and to many classes, at some point you will have unexpected conversion or ambiguities. Making some conversion explicit can limit the problem. Usually is it best to use explicite conversion as it was done by experts in std::string
. You have to call member function c_str()
if you want a C style string.
For example, since your StringType
class define conversion to both const char *
and QString
, then if you have a method that accept both (maybe an Append function), then you have a conflict.
If you really want conversion, then use named method instead (for ex. AsQString()
, c_str()
, tostdstring()
...). It help ensure that all conversion are intended. It make it easier to find them and it is certainly better that explicit cast like you have done in a few place in your code. While static_cast
and other casts are sometime useful, then can also hide some problem when code is refactored as in some case, the cast might compile while not being correct. This would be the case if you cast to a derived class and at some point decide to change the derived class for something else and forget to update some casts.
You should select the most appropriate string for your application and do conversion when required. In a large application, you might use one type for the UI (ex. CString or QString) while using standard string in librairies that are shared across platforms or with third party library. Some time those libraries have their own string class too. Your selection should try minimize useless conversions.
I can't thank you enough for your precious time. If you feel like to spend more time please check my updated questions. Have a nice day.
– Shabbir Ahmed
Nov 16 '18 at 7:06
add a comment |
For your question:
- It is usually best to avoid implicit conversion. Also you won't be able to reuse
std::string
operators like +, += with that kind of approach without adding a lot one line function. The wrapper class bring you nothing except adding more conversions as you would then use you new string type and with the mixin approach, this is even worst as you need to also convert between your own types. - Why would you use virtual inheritance? Do you really want to derive from multiple classes that have a common base and that have their own data.
- As this is a bad design, you probably won't find many people doing it. Your design increase coupling, lead to class proliferation, increase type conversions and make maintenance harder among other things.
- I believe, there is no such thing.
For simple functions like those above, the preferred approach would be to define a namespace (or many if you have a lot of functions that could somehow be categorized like maybe file name manipulation) and then have free functions inside it.
By using a namespace, you have a few advantages:
- If you call a lot of functions, you can always add an using statement inside your function or source file (never in a header file).
- Auto suggestion will work well to find those function.
If some of the original mixin maintain state, then you should do an helper class. This could be the case for a class like an HTML builder that might have functions like AddTag, Add Attribute, AddEncodedUrl etc that could be used to create an HTML document.
One big advantage of this approach is that coupling is much looser than in your design. For example, a file pair (header and source) would contains all functions used for the Printer. If you need that, you don't have to create a new class that use some combination of mixin.
One big problem with your approach, is that with time you will have a lot of different StringType<…>
If you have 5 mixins that could be used, you have 2^5 = 32 classes. At that point, it is almost sure that you will often need the mixin you didn't include and then you have cascading change if the call it deep. And if you use template everywhere then you will have compilation slowdown and probably some code bloat.
Implicit conversion is also considered to be best avoid in most cases by most experts. If you have multiple conversion from and to many classes, at some point you will have unexpected conversion or ambiguities. Making some conversion explicit can limit the problem. Usually is it best to use explicite conversion as it was done by experts in std::string
. You have to call member function c_str()
if you want a C style string.
For example, since your StringType
class define conversion to both const char *
and QString
, then if you have a method that accept both (maybe an Append function), then you have a conflict.
If you really want conversion, then use named method instead (for ex. AsQString()
, c_str()
, tostdstring()
...). It help ensure that all conversion are intended. It make it easier to find them and it is certainly better that explicit cast like you have done in a few place in your code. While static_cast
and other casts are sometime useful, then can also hide some problem when code is refactored as in some case, the cast might compile while not being correct. This would be the case if you cast to a derived class and at some point decide to change the derived class for something else and forget to update some casts.
You should select the most appropriate string for your application and do conversion when required. In a large application, you might use one type for the UI (ex. CString or QString) while using standard string in librairies that are shared across platforms or with third party library. Some time those libraries have their own string class too. Your selection should try minimize useless conversions.
I can't thank you enough for your precious time. If you feel like to spend more time please check my updated questions. Have a nice day.
– Shabbir Ahmed
Nov 16 '18 at 7:06
add a comment |
For your question:
- It is usually best to avoid implicit conversion. Also you won't be able to reuse
std::string
operators like +, += with that kind of approach without adding a lot one line function. The wrapper class bring you nothing except adding more conversions as you would then use you new string type and with the mixin approach, this is even worst as you need to also convert between your own types. - Why would you use virtual inheritance? Do you really want to derive from multiple classes that have a common base and that have their own data.
- As this is a bad design, you probably won't find many people doing it. Your design increase coupling, lead to class proliferation, increase type conversions and make maintenance harder among other things.
- I believe, there is no such thing.
For simple functions like those above, the preferred approach would be to define a namespace (or many if you have a lot of functions that could somehow be categorized like maybe file name manipulation) and then have free functions inside it.
By using a namespace, you have a few advantages:
- If you call a lot of functions, you can always add an using statement inside your function or source file (never in a header file).
- Auto suggestion will work well to find those function.
If some of the original mixin maintain state, then you should do an helper class. This could be the case for a class like an HTML builder that might have functions like AddTag, Add Attribute, AddEncodedUrl etc that could be used to create an HTML document.
One big advantage of this approach is that coupling is much looser than in your design. For example, a file pair (header and source) would contains all functions used for the Printer. If you need that, you don't have to create a new class that use some combination of mixin.
One big problem with your approach, is that with time you will have a lot of different StringType<…>
If you have 5 mixins that could be used, you have 2^5 = 32 classes. At that point, it is almost sure that you will often need the mixin you didn't include and then you have cascading change if the call it deep. And if you use template everywhere then you will have compilation slowdown and probably some code bloat.
Implicit conversion is also considered to be best avoid in most cases by most experts. If you have multiple conversion from and to many classes, at some point you will have unexpected conversion or ambiguities. Making some conversion explicit can limit the problem. Usually is it best to use explicite conversion as it was done by experts in std::string
. You have to call member function c_str()
if you want a C style string.
For example, since your StringType
class define conversion to both const char *
and QString
, then if you have a method that accept both (maybe an Append function), then you have a conflict.
If you really want conversion, then use named method instead (for ex. AsQString()
, c_str()
, tostdstring()
...). It help ensure that all conversion are intended. It make it easier to find them and it is certainly better that explicit cast like you have done in a few place in your code. While static_cast
and other casts are sometime useful, then can also hide some problem when code is refactored as in some case, the cast might compile while not being correct. This would be the case if you cast to a derived class and at some point decide to change the derived class for something else and forget to update some casts.
You should select the most appropriate string for your application and do conversion when required. In a large application, you might use one type for the UI (ex. CString or QString) while using standard string in librairies that are shared across platforms or with third party library. Some time those libraries have their own string class too. Your selection should try minimize useless conversions.
For your question:
- It is usually best to avoid implicit conversion. Also you won't be able to reuse
std::string
operators like +, += with that kind of approach without adding a lot one line function. The wrapper class bring you nothing except adding more conversions as you would then use you new string type and with the mixin approach, this is even worst as you need to also convert between your own types. - Why would you use virtual inheritance? Do you really want to derive from multiple classes that have a common base and that have their own data.
- As this is a bad design, you probably won't find many people doing it. Your design increase coupling, lead to class proliferation, increase type conversions and make maintenance harder among other things.
- I believe, there is no such thing.
For simple functions like those above, the preferred approach would be to define a namespace (or many if you have a lot of functions that could somehow be categorized like maybe file name manipulation) and then have free functions inside it.
By using a namespace, you have a few advantages:
- If you call a lot of functions, you can always add an using statement inside your function or source file (never in a header file).
- Auto suggestion will work well to find those function.
If some of the original mixin maintain state, then you should do an helper class. This could be the case for a class like an HTML builder that might have functions like AddTag, Add Attribute, AddEncodedUrl etc that could be used to create an HTML document.
One big advantage of this approach is that coupling is much looser than in your design. For example, a file pair (header and source) would contains all functions used for the Printer. If you need that, you don't have to create a new class that use some combination of mixin.
One big problem with your approach, is that with time you will have a lot of different StringType<…>
If you have 5 mixins that could be used, you have 2^5 = 32 classes. At that point, it is almost sure that you will often need the mixin you didn't include and then you have cascading change if the call it deep. And if you use template everywhere then you will have compilation slowdown and probably some code bloat.
Implicit conversion is also considered to be best avoid in most cases by most experts. If you have multiple conversion from and to many classes, at some point you will have unexpected conversion or ambiguities. Making some conversion explicit can limit the problem. Usually is it best to use explicite conversion as it was done by experts in std::string
. You have to call member function c_str()
if you want a C style string.
For example, since your StringType
class define conversion to both const char *
and QString
, then if you have a method that accept both (maybe an Append function), then you have a conflict.
If you really want conversion, then use named method instead (for ex. AsQString()
, c_str()
, tostdstring()
...). It help ensure that all conversion are intended. It make it easier to find them and it is certainly better that explicit cast like you have done in a few place in your code. While static_cast
and other casts are sometime useful, then can also hide some problem when code is refactored as in some case, the cast might compile while not being correct. This would be the case if you cast to a derived class and at some point decide to change the derived class for something else and forget to update some casts.
You should select the most appropriate string for your application and do conversion when required. In a large application, you might use one type for the UI (ex. CString or QString) while using standard string in librairies that are shared across platforms or with third party library. Some time those libraries have their own string class too. Your selection should try minimize useless conversions.
answered Nov 16 '18 at 3:16
Phil1970Phil1970
1,3581810
1,3581810
I can't thank you enough for your precious time. If you feel like to spend more time please check my updated questions. Have a nice day.
– Shabbir Ahmed
Nov 16 '18 at 7:06
add a comment |
I can't thank you enough for your precious time. If you feel like to spend more time please check my updated questions. Have a nice day.
– Shabbir Ahmed
Nov 16 '18 at 7:06
I can't thank you enough for your precious time. If you feel like to spend more time please check my updated questions. Have a nice day.
– Shabbir Ahmed
Nov 16 '18 at 7:06
I can't thank you enough for your precious time. If you feel like to spend more time please check my updated questions. Have a nice day.
– Shabbir Ahmed
Nov 16 '18 at 7:06
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53329850%2fmeta-mixin-is-that-even-a-thing-template-meta-programming%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I would say it is the wrong approach… Use a namespace with free function or if the code is more complex, use an helper class. For example:
namespace Printer { void print(const string &s) { std::cout << "From the printer: " << s; } }
– Phil1970
Nov 16 '18 at 1:18
@Phil1970
print()
ortoString()
is rally not my concern. Please see in my code that operator overloading (assignment & casting) and constructor conversion is the main feature here since it wraps different string implementation. Will be very glad if reconsider to check again my approach. Thanks.– Shabbir Ahmed
Nov 16 '18 at 1:41
1
Well your implementation forces UB. So that is bad.
– Yakk - Adam Nevraumont
Nov 16 '18 at 1:58
Fix;
mixin_t<StringType<mixin_t...>>...
– Yakk - Adam Nevraumont
Nov 16 '18 at 2:09
1
@shabb CRTP is unsafe and unchecked.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:04