I am purposely using the dot and arrow operator incorrectly, but I'm confused why it compiles when I decide to make the class a template.
Compiles:
template <class B>
struct Boss {
bool operator==( Boss & other ) {
return this.x == other -> x;
}
};
int main() {
}
Does not compile:
struct Boss {
bool operator==( Boss & other ) {
return this.x == other -> x;
}
};
int main() {
}
Templates are not fully checked for correctness if they are not instantiated. They are only checked for syntax. this.x, while not semantically correct (because this is not, and cannot be a type that supports that operation), is still syntactically correct.
It compiles because templates are not checked until you use it. If you try to do something useful in your main(), it will give you a compile error.
Related
I work on a code base where the C++ API is about to change (master branch and feature branch) and I want to protect my code against the change, such that my code builds against both versions. As minimum working example godbolt/compiler-explorer link:
common:
class SmallWidget {
private:
int m_i;
public:
int i() { return m_i; }
};
master:
class BigWidget {
private:
std::vector<SmallWidget*> m_v;
public:
auto& widgets() { return m_v; }
};
feature branch:
class BigWidget {
private:
std::vector<SmallWidget> m_v;
public:
auto& widgets() { return m_v; }
};
/**/
For the master version I have some call code:
int single_op(BigWidget& w) {
return (*w.widgets().begin())->i(); // asterisk will need to go
}
std::vector<int> do_stuff(std::vector<BigWidget> inputs) {
std::vector<int> retval;
for (auto w : inputs) {
retval.push_back(single_op(w));
}
return retval;
}
The API does not come with a preprocessor variable to select with
#if WIDGET_VERSION == OLD
return (*w.widgets().begin())->i(); // asterisk will need to go
#else
return (w.widgets().begin())->i(); // asterisk gone
#endif
I was trying to detect the return type of widgets with sfinae:
// version for the master branch API
template <typename = typename std::enable_if<std::is_same<
std::remove_const<std::remove_reference<decltype(**(
std::declval<BigWidget>().widgets().begin()))>::type>::type,
SmallWidget>::value>::type>
int single_op(BigWidget& w) {
return (*w.widgets().begin())->i();
}
// version for the feature branch API
template <typename = typename std::enable_if<std::is_same<
std::remove_const<std::remove_reference<decltype(*(
std::declval<BigWidget>().widgets().begin()))>::type>::type,
SmallWidget>::value>::type>
int single_op(BigWidget& w) { return w.widgets().begin()->i(); }
But the compilers are not happy about that. clang says:
<source>:43:46: error: failed requirement 'std::is_same<std::remove_const<std::remove_reference<decltype(* (std::declval<BigWidget>().widgets().begin()))>::type>::type, SmallWidget>::value'; 'enable_if' cannot be used to disable this declaration
template
Is there a way to use sfinae to enable the right code here?
I also tried using std::enable_if for the return code or function arguments, but my understanding is that the compiler always sees the signature int single_op(BigWidget&) for both versions.
Create a small helper function that will take either type and return the type you want.
SmallWidget &getWidget(SmallWidget *w) { return *w; }
SmallWidget &getWidget(SmallWidget &w) { return w; }
int single_op(BigWidget &w) {
return getWidget(*w.widgets().begin()).i();
}
You can also provide overloads for const versions.
I could come up with this version:
// version for the feature branch API
template <typename bigtype>
int single_op(
typename std::enable_if<
std::is_same<
std::remove_const<std::remove_reference<decltype(
*(std::declval<BigWidget>().widgets().begin()))>::type>::type,
SmallWidget>::value,
bigtype>::type& w) {
return w.widgets().begin()->i();
}
I added one additional template argument for the BigWidget type (despite being known) and use it for the function argument of single_op. Now the compiler can go through both template definitions, arrive with one possible solution for the overload set and disables the unused code.
As drawback, I now have to spell out the template argument on the call side
retval.push_back(single_op<decltype(w)>(w));
But I suspect there are better solutions out there.
The only way I can get this to compile without issuing a warning on no member a when T==B and so on for T==A is to reinterpret_cast within the if statement blocks and access the non-shared members via a pointer. Is there no way to get around this or hint to the compiler otherwise?
This is gcc 4.8.x
enum Type { A, B};
template<Type T> struct S { };
template<> struct S<A> { int x; int a; };
template<> struct S<B> { int y; int x; int b; };
template<Type T> static void foo(int x)
{
// lots of code
S<T> s;
s.x = someCall();
if (T == A)
{
s.a = 1;
}
else if (T == B)
{
s.y = 2;
s.b = 3;
}
// a bunch of common code
}
Edit: I know about making a dedicated specific functions to handle the specifics but I was hoping to avoid extra boilerplate code.
You may use specialization:
template <Type T> void bar(S<T>&);
template <> void bar(S<A>& s) {s.a = 1;}
template <> void bar(S<B>& s) {s.y = 2; s.b = 3;}
template<Type T> static void foo(int x)
{
// lots of code
S<T> s;
s.x = someCall();
bar(s);
// a bunch of common code
}
if (T == A)
[...]
else if (T == B)
[...]
A, B and T here are compile-time entities, not run-time entities. And yet you are attempting to perform a run-time evaluation of something that is known at compile time. Now sure, you could try to hack up something with a kind of iffy cast (try, and fail), or try some other kind of kludgery, but the code is telling you: you're doing it wrong.
Specializing foo is one way, as may be levarging SFINAE (as with enable_if), but from what little I can see here of your use case, that would be doing it wrong too. That's because the code you look to be implementing is some kind of initialization code, or code that manipulates the internal state of the object being used. In a sense, you're violating the principle of single responsibility.
So move that code to where the responsibility belongs: in the class that's being inited.
template<> struct S<A> { int x; int a; void init() {a=1;} };
template<> struct S<B> { int y; int x; int b; void init() { x=2; y=3; } };
template<Type T> static void foo(int x)
{
// lots of code
S<T> s;
s.x = someCall();
s.init();
// a bunch of common code
}
You could also use a factory class. This would abstract away both the instantiation of the object, and the call to init(), which can take different parameters depending on the ultimate type.
-edit- I narrowed it down. Reproducible: Why does passing this object in C break my code?
My app is not working properly after i made a change. I got a warning in msvc but not in gcc.
Heres a repo of the warning.
warning C4190: 'fnA' has C-linkage specified, but returns UDT 'Test' which is incompatible with C
#include <type_traits>
template<class T>
class Test{
T t;
};
typedef Test<int> A;
//static_assert(std::is_pod<A>::value, "Not a POD"); //fails in msvc 2010
static_assert(sizeof(A) == sizeof(int), "");
static_assert(sizeof(A) == sizeof(void*), "");
extern "C" {
A fnA(A v) { return v; }
}
int main() {
A a;
fnA(a);
}
AFAIK there should be no reason why i can't use Test as a return value; This may not be the problem but this may be the problem. I can't figure out the problem but i get runtime oddities that i can not reproduce (both gcc and msvc). I suspected the problem would be MyString is corrupted but it appears that isnt the case which made me quite confused. Heres my wrapper. MyString is >8bytes and i need to hand this off to C code which returns everything by int unfortunately. Which is why i put the static assert to see if the class size is what i expected. Now that size/splicing is handled, i'm still completely like WTF!?! Why does that warning exist and is there anything i can possibly do to fix it?
Even writing class Test{ T t; }; causes the warning however struct fixes it. struct with private breaks it and i need t to be private.
OK! After I removed the constructors in WrappedPointer and changed the class to struct (which makes lhs public). It runs perfectly in GCC and MSVC. Changing struct WrappedPointer to class WrappedPointer breaks my code. WTF!?! This is a debug build too, not optimized. Why on earth does changing the keyword struct to class break the code!?! WTF!?! BUT that change doesnt break gcc. Using non default constructors break gcc...
template <class T>
struct WrappedPointer {
//private:
T* lhs;
public:
void SetLHS(T*v) { lhs=v; }
//WrappedPointer(){}
//WrappedPointer(T*value) : lhs(value){}
//WrappedPointer(const WrappedPointer&v) : lhs(v.lhs){}
T* operator->() const { return lhs; }
T* operator*() const { return lhs; }
template<class TT>
bool operator==(TT t) const { return *lhs==t; }
template<class TT>
bool operator!=(TT t) const { return *lhs!=t; }
bool operator==(int v) const { myassert2(v==0); return lhs==0; }
bool operator!=(int v) const { myassert2(v==0); return lhs!=0; }
bool operator==(const WrappedPointer&t) const { return *lhs==*t; }
bool operator!=(const WrappedPointer&t) const { return *lhs!=*t; }
}
typedef WrappedPointer<MyString> String;
//typedef MyString* String;
static_assert(sizeof(String) == sizeof(int), "");
static_assert(sizeof(String) == sizeof(void*),"");
The external "C" marks the function to have C linkage and disables name mangling. Now the issue in your function is that the argument is a template (the typedef only creates an alias in the current translation unit, A is still Test<int> for all purposes), and that name must be mangled.
extern "C" {
A fnA(A v) { return v; }
}
This says that fnA is a C function. C does not have object-oriented programming, or templates. The function uses both. Therefore, it cannot link as a C function.
Classes are not valid in C.
Templates are not valid in C.
Templated classes are certainly not valid in C.
Pick your language and stick to it!
I have this "better" enum class that
cannot contain invalid values, and
cannot be used until enum value is not set explicitly,
as follows:
class Symmetry
{
public:
enum Type {
GENERAL, SYMMETRIC, HERMITIAN,
SKEW_SYMMETRIC, SKEW_HERMITIAN, UNINITIALIZED
};
Symmetry() { t_ = UNINITIALIZED }
explicit Symmetry(Type t) : t_(t) { checkArg(t); }
Symmetry& operator=(Type t) { checkArg(t); t_ = t; return *this; }
operator Type() const {
if (t_ == UNINITIALIZED) throw runtime_error("error");
return t_;
}
private:
Type t_;
void checkArg(Type t) {
if ((unsigned)t >= (unsigned)UNINITIALIZED)
throw runtime_error("error");
}
};
This allows me to write the following code:
Symmetry s1(Symmetry::SYMMETRIC);
Symmetry s2;
s2 = Symmetry::HERMITIAN;
Symmetry s3;
if (Symmetry::GENERAL == s3) // throws
My problem is that a compiler allows constructs such as:
Symmetry s1((Symmetry::Type)18); // throws
Symmetry s2;
s2 = (Symmetry::Type)18; // throws
I solved this problem by throwing exceptions, but I would prefer such a code not to compile at all (a compile time error). Is there a way how to manage this?
Potentially a crummy solution, but it would solve your immediate problem. Rather than having an inner enum type, define a little helper class with a private constructor, and make the outer class a friend. Then the "enum" values can be static const members in your outer class. Something like this:
(DISCLAIMER: untested, so there may be various compilation issues, but you should get the idea)
class Symmetry
{
public:
class Type
{
private:
Type() {};
friend class Symmetry;
};
static const Type GENERAL;
static const Type SYMMETRIC;
static const Type HERMITIAN;
};
You will need some way of determining equality, but this should be fairly easy.
My attempt using templates: (tested. However, this can be further improved!)
template<int N>
struct Symmetry
{
enum Type
{
GENERAL, SYMMETRIC, HERMITIAN,
SKEW_SYMMETRIC, SKEW_HERMITIAN
};
template<Type e> struct allowed;
template<> struct allowed<GENERAL> { static const int value = GENERAL; };
template<> struct allowed<SYMMETRIC> { static const int value = SYMMETRIC; };
template<> struct allowed<HERMITIAN> { static const int value = HERMITIAN; };
template<> struct allowed<SKEW_SYMMETRIC> { static const int value = SKEW_SYMMETRIC; };
template<> struct allowed<SKEW_HERMITIAN> { static const int value = SKEW_HERMITIAN; };
allowed<(Type)N> m_allowed;
operator int()
{
return N;
}
};
Symmetry<0> e0; //okay
Symmetry<1> e1; //okay
Symmetry<100> e4; //compilation error!
Symmetry<e0.SKEW_HERMITIAN> e3; //okay
Symmetry<e0.SKEW_SYMMETRIC> e3; //okay
Usage:
int main()
{
Symmetry<0> e0;
Symmetry<e0.HERMITIAN> e1;
switch (e1)
{
case e0.HERMITIAN:
{
cout << "It's working" << endl;
}
break;
}
}
No. If you allow any cast to be used, as your last example does, then there will always be some cast that can be used to subvert your type.
The solution is to not be in the habit of using these casts and to very suspiciously consider any code that uses these casts indiscriminately. View this type of casting as the nuclear bomb in your arsenal: it's important to have, but you always handle it with care and never want to deploy it more than rarely.
What warning options does your compiler have for casting? What lint tools are you using which may detect this misuse of casts?
That said, it appears you really want to hide the inner Type so users are less tempted to even use it. Realizing that, it's straight-forward to make that type name private, even while not preventing all cast misuse, by slightly tweaking your original:
struct Symmetry {
enum {
UNINITIALIZED,
GENERAL, SYMMETRIC, HERMITIAN,
SKEW_SYMMETRIC, SKEW_HERMITIAN
};
private:
typedef decltype(UNINITIALIZED) Hidden;
Hidden _value;
public:
Symmetry(Hidden value = UNINITIALIZED) : _value (value) {}
Symmetry& operator=(Hidden value) { _value = value; return *this; }
operator Hidden() const {
if (_value == UNINITIALIZED) {
throw std::logic_error("uninitialized Symmetry");
}
return _value;
}
bool initialized() const { return _value != UNINITIALIZED; }
// required if you want to check for UNINITIALIZED without throwing in
// the above conversion
};
This is a complete implementation, no details omitted or unknown, or issues with initialization order. The only caveat is decltype – with a pre-C++0x compiler, you'll have to use something implementation-specific or a library which wraps something implementation-specific.
And a smaller issue: change from runtime_error to logic_error, as using uninitialized values should be preventable beforehand and thus falls in the latter category.
I would like to know what is better to use in my situation and why. First of all I heard that using RTTI (typeid) is bad. Anyone could explain why? If I know exactly types what is wrong to compare them in a runtime? Furthermore is there any example how to use boost::type_of? I have found none searching through the mighty google :) Other solution for me is specialization, but I would neet to specialize at least 9 types of new method. Here is an example what I need:
I have this class
template<typename A, typename B, typename C>
class CFoo
{
void foo()
{
// Some chunk of code depends on old A type
}
}
So I need to rather check in typeid(what is I heard is BAD) and make these 3 realizations in example like:
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
So what is the best solution? I don't want to specialize for all A,B,C, because every type is has 3 specializations so I will get 9 methods or just this typeid check.
It's bad because
A, B and C are known at compile-time but you're using a runtime mechanism. If you invoke typeid the compiler will make sure to include metadata into the object files.
If you replace "Do this chunk of code related to A type" with actual code that makes use of CSomeClass's interface you'll see you won't be able to compile the code in case A!=CSomeClass and A having an incompatible interface. The compiler still tries to translate the code even though it is never run. (see example below)
What you normally do is factoring out the code into separate function templates or static member functions of classes that can be specialized.
Bad:
template<typename T>
void foo(T x) {
if (typeid(T)==typeid(int*)) {
*x = 23; // instantiation error: an int can't be dereferenced
} else {
cout << "haha\n";
}
}
int main() {
foo(42); // T=int --> instantiation error
}
Better:
template<typename T>
void foo(T x) {
cout << "haha\n";
}
void foo(int* x) {
*x = 23;
}
int main() {
foo(42); // fine, invokes foo<int>(int)
}
Cheers, s
Well generally solutions can be come up with without RTTI. It "can" show you haven't thought the design of the software out properly. THAT is bad. Sometimes RTTI can be a good thing though.
None-the-less there IS something odd in what you want to do. Could you not create an interim template designed something like as follows:
template< class T > class TypeWrapper
{
T t;
public:
void DoSomething()
{
}
};
then partially specialise for the functions you want to as follows:
template<> class TypeWrapper< CSomeClass >
{
CSomeClass c;
public:
void DoSomething()
{
c.DoThatThing();
}
};
Then in your class define above you would do something such as ...
template
class CFoo
{
TypeWrapper< A > a;
TypeWrapper< B > b;
TypeWrapper< C > c;
void foo()
{
a.DoSomething();
b.DoSomething();
c.DoSomething();
}
}
This way it only actually does something in the "DoSomething" call if it is going through the partially specialised template.
The problem lies in the code chunks you write for every specialization.
It doesn't matter if you write (lengthwise)
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
or
void foo()
{
A x;
foo_( x );
B y;
foo_( y );
C z;
foo_( z );
}
void foo_( CSomeClass1& ) {}
void foo_( CSomeClass2& ) {}
void foo_( CSomeClass3& ) {}
The upside of the second case is, when you add a class D, you get reminded by the compiler that there is an overload for foo_ missing which you have to write. This can be forgotten in the first variant.
I'm afraid this is not going to work in the first place. Those "chunks of code" have to be compilable even if the type is not CSomeClass.
I don't think type_of is going to help either (if it is the same as auto and decltype in C++0x).
I think you could extract those three chunks into separate functions and overload each for CSomeClass. (Edit: oh there are else if's. Then you might indeed need lots of overloads/specialization. What is this code for?)
Edit2: It appears that your code is hoping to do the equivalent of the following, where int is the special type:
#include <iostream>
template <class T>
bool one() {return false; }
template <>
bool one<int>() { std::cout << "one\n"; return true; }
template <class T>
bool two() {return false; }
template <>
bool two<int>() { std::cout << "two\n"; return true; }
template <class T>
bool three() {return false; }
template <>
bool three<int>() { std::cout << "three\n"; return true; }
template <class A, class B, class C>
struct X
{
void foo()
{
one<A>() || two<B>() || three<C>();
}
};
int main()
{
X<int, double, int>().foo(); //one
X<double, int, int>().foo(); //two
X<double, double, double>().foo(); //...
X<double, double, int>().foo(); //three
}
I think you've got your abstractions wrong somewhere.
I would try redefining A, B & C in terms of interfaces they need to expose (abstract base classes in C++ with pure virtual methods).
Templating allows basically duck-typing, but it sounds like CFoo knows too much about the A B & C classes.
typeid is bad because:
typeid can be expensive, bloats
binaries, carries around extra
information that shouldn't be
required.
Not all compilers support it
It's basically breaking the class hierarchy.
What I would recommend is refactoring: remove the templating, instead define interfaces for A, B & C, and make CFoo take those interfaces. That will force you to refactor the behaviour so the A, B & C are actually cohesive types.