c++ using struct enum as a parameter won't compile - c++

If create an enum inside a struct for readability, mentioned here
How to avoid name conflicts for two enum values with the same name in C++?
I am planning to add more enums, here and in other situations, I just wanted to know why the struct wasn't compiling. Coming from C# and Java I was hoping for a simpler syntax –
And have the struct as the parameter to a constructor in a class, I cannot call it from the main.cpp of a console application.
It gives me the error **no matching function for call toBarEnc::BarEnc(BarEnc::Scheme::eScheme)’ ** main.cpp
Here is the Class
class BarEnc {
public:
struct Scheme
{
enum eScheme
{ ADJ1M2, ADJ3M6
};
};
BarEnc();
BarEnc(BarEnc::Scheme scheme);
}
in main.cpp
I call it
BarEnc barEnc = BarEnc(BarEnc::Scheme::ADJ3M6);
But if I change the parameter to an int in the constructor the code compiles
BarEnc(int scheme);
If I change it to the enum the code compiles
BarEnc(BarEnc::Scheme::eScheme scheme);
But when it is a struct, it does not compile. I am relative new to C++, using GCC 4.6 to compile on Linux, using 99 standard.
Is there a reason why I can't use a struct as a parameter?

Simple question: how your enum value should be converted to struct?
Simple answer: there is no way, since there is no suitable constructor.
Your struct has no members, it has only type (enum), so, I have no idea, what you want to do.

When you declare the constructor as
BarEnc(BarEnc::Scheme scheme);
you tell the compiler that the BarEnc constructor takes a structure as argument, and so you can't pass the enumeration value as it's an enumeration and not the structure.
In this case there is really no use for a separate structure just to define the enumeration, you can declare it directly in the surrounding class:
class BarEnc {
public:
enum eScheme {
ADJ1M2,
ADJ3M6
};
BarEnc(eShceme scheme);
};
Then when creating BarEnc objects you pass the enumeration value:
BarEnc barenc(BarEnc::eScheme::ADJ1M2);

You can use a struct as parameter.
But your struct BarEnc::Scheme in fact has no member.
and the const value BarEnc::Scheme::ADJ3M6 's type is BarEnc::Scheme::eScheme, it cannot auto convert to a struct.

Related

How to convert a template definition into a class

The following code works when used without C++ classes (Arduino code);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiA);
This creates a variable midiA with the correct type. The macro definition is:
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \
midi::MidiInterface<Type> Name((Type&)SerialPort);
However, I want to use this inside a class (to create a class variable midiA), but I cannot get it to work.
What I have now is:
class MidiHandler
{
midi::MidiInterface<(HardwareSerial&) Serial1)> midiA;
}
However, I get the following error:
MidiHandler.h: 23:39: error: type\value mismatch at argument 1 in template parameter list for 'template<class SerialPort, class _Settings> class midi::MidiInterface
midi*: MidiInterface<((HardwareSerial&)Serial1)> midiA
I think I might need to add the template to the class MidiHandler, also I wonder if I need to initialize it in the constructor.
Disclaimer: I don't have an Arduino to compile and test this, but from the pure C++ point of view, I would declare the member in the class declaration and initialize it in the constructor. Like this:
class MidiHandler
{
public:
MidiHandler(HardwareSerial& serial_port)
: midiA(serial_port)
{ }
private:
midi::MidiInterface<HardwareSerial> midiA;
};
Then, instantiate the class like this:
MidiHandler handler((HardwareSerial&) Serial1);
DETAIL:
The MidiHandler class has a member variable named midiA of type midi::MidiInterface<HardwareSerial>, which is a template with one template parameter (the Type parameter from the macro). HardwareSerial is used as the value for the template parameter.
The type midi::MidiInterface<HardwareSerial> has a constructor requiring one parameter of type HardwareSerial&. Therefore, MidiHandler::MidiHandler, the MidiHandler class constructor, needs a parameter of the same type to be used to construct midiA.
Finally, Serial1 is passed as the constructor parameter to handler. Serial1 must be of type HardwareSerial& or convertible to it. The C stile cast, (HardwareSerial&), may or may not be needed depending on the type of Serial1, but I put it there since the macro had it.
As is shown in the define:
#define MIDI_CREATE_INSTANCE(Type, SerialPort, Name)
midi::MidiInterface<Type> Name((Type&)SerialPort);
So substituting in Your values should be:
midi::MidiInterface<HardwareSerial> midiA((HardwareSerial&)Serial1);
Answer as result of the accepted answer by Luis Guzman:
In header file:
midi::MidiInterface<HardwareSerial> midiA;
midi::MidiInterface<HardwareSerial> midiB;
midi::MidiInterface<HardwareSerial> midiC;
In constructor:
MidiHandler::MidiHandler()
: midiA(Serial1),
midiB(Serial2),
midiC(Serial3)

Typedef to surrounding type in C++

Is there a way to build a typedef inside a type declaration to the declared (surrounding) type itself without stating the type's name?
Example:
class X
{
public:
typedef <fill in magic here> MyType;
//...
};
Background:
This seems silly on the first look. I need this because I build compile-time-reflection of my data classes using macros.
So there is a macro inserted into the declaration of the data class which needs to deal with the type it is inserted into.
So far I found working solutions for MSVC and g++ which both rely on what I think are flaws in the implementation. So they may not work on a newer version.
Clang does not "eat" either of these solutions.
My current solution for MSVC defines a method and then takes it's address only by it's name and calls a small helper that "returns" the type of it's class. (Clang and g++ expect the full name of the method including it's class name).
My current solution for g++ defines a static method with return type std::remove_reference(decltype(*this)). (Clang and MSVC do not allow this in the static context).
I would absolutely prefer a standard conform solution but a special solution for clang would also be ok for the moment.
If nothing works I have to pass the class' name to the macro but I try to avoid this since I already have plenty of code using the macro.
EDIT: Adding a sample on how the reflection works (which may clarify what I need):
class X : public Y
{
public:
//.. constructor and such stuff...
int a;
double b;
std::string c;
CLASSHEAD(Y)
FIELD(a)
FIELD(b)
FIELD(c)
CLASSFOOT
};
CLASSHEAD is the macro that should define typedef. It is a VAR_ARGS macro where the arguments receive the base classes. As said: It is possible to give it the class' name as it's first argument (resulting in CLASSHEAD(X, Y) in the example). But I nearly cannot imagine that there is no solution to such a "simply" task as typedef'ing the surrounding type...
This doesn't exactly meet your specification, but I think its pretty close:
class X
{
//Stuff...
//Use Macros to add:
struct MyType;
//Use class closing macro to insert variable between class-ending brace and semicolon
} TYPE_VAR;
//Perhaps add random stuff to TYPE_VAR name to avoid collisions, like __FILE__
struct decltype(TYPE_VAR)::MyType
{
typedef decltype(TYPE_VAR) V;
};
Then access X's type using
X::MyType::V
For example, a simplified CLASSFOOT might look like this:
#define CLASSFOOT /*Your classfoot here*/ } TYPE_VAR; struct decltype(TYPE_VAR)::MyType {typedef decltype(TYPE_VAR) V;
//No }; at end on purpose- this will come from the class in which you placed CLASSFOOT
Is this good enough for your purposes?
Since you are already using macros, you could use this solution https://stackoverflow.com/a/21143997/2173029
#define CLASS_WITH_MY_TYPE(ClassName) \
class ClassName \
{ \
using MyType = ClassName;
And then use like
CLASS_WITH_MY_TYPE(X)
public:
struct Y
{
using T = MyType;
};
};
static_assert(std::is_same<X, typename X::Y::T>::value, "");
Marked as community wiki since #Chris mentioned the link and the original answer was posted by #Bartek Banachewicz
Nohting works so using the class Name in the macro is the only working solution

Class containing template dependent on the class member

The goal is to make kind of "smart getter" that gets the value from the current object if it is present, if not, it looks for the value in the parent object.
So this ValueGetter class contains pointer to the object it is contained in (gets it as run time parameter in constructor) and pointer to member it operates on as template parameter.
This is the most simple example:
template <class StyleType, int StyleType::*value>
struct ValueGetter
{
ValueGetter(StyleType* containedIn);
int get();
// Looks if the value is present in this style,
// if not it looks for the value in the parent style
};
struct Style
{
Style *parent;
int a;
ValueGetter<Style, &Style::a> x; // Error: 'Style::a' : is not a type name, static, or enumerator
};
When I move the x outside of the scope of the class, it compiles.
Generally it is possible for class to contain template dependent on the class type, so why this doesn't work?
Is there any other way to solve this issue without storing the pointer to member in runtime in constructor? (So the structure would contain extra pointer for every value)
Edit: I just succesfully compiled it in GCC, but not in MSVC (2012), so is this MSVC compiler error?
I don't think pointers (not to confuse with pointer types as in T*) are allowed as template parameters in 03 C++, only type names, integral constants or enum constants. Not even float/double constants. That includes class member pointers.
Update:
Also, static non-type parameters work:
template <class StyleType, int *value>
struct ValueGetter
{
ValueGetter(StyleType* containedIn);
int get();
// Looks if the value is present in this style,
// if not it looks for the value in the parent style
};
struct Style
{
Style *parent;
static int a;
ValueGetter<Style, &Style::a> x; // Error: 'Style::a' : is not a type name, static, or enumerator
};

Set variable type for a c++ class variable during instantiation

I have a c++ class such as the following:
class some_class {
protected:
decide_later some_variable;
public:
void some_random_function();
};
void some_class::some_random_function() {
decide_later another_variable;
}
The problem is that I don't know what variable type some_variable will be until I create an instance of the class. What I want to do is something like the following:
some_class class_instance(std::string);
And that would set decide_later to use std::string (or int, or double, or whatever it is told to use). In addition, it would be great if I could use decide_later as a variable type later on in other functions that are members of the class. For example, in the function some_random_function().
I have tried using boost::any to do this, but it seems to only work for numeric types. Besides, I think it would be more efficient if I could actually set the actual variable type.
Is this possible?
You are looking for templates. Declare your class like:
template <typename T> class some_class {
protected:
T some_variable;
public:
void some_random_function() {
T another_variable;
}
};
and instantiate it with:
some_class<std::string> class_instance();
If you know the type statically when you create the instance, you should use C++ templates and make the type a template parameter.
If you know it only dynamically (i.e. based on user input), you can either branch then and instantiate the template with different type parameters, or you can go for a completely dynamical solution (like boost::any or equivalent).
However, I believe that if you can't do this with templates then there's something wrong in your program design. The idea of C++ static typing is that types are known at compile time. Normally in object-oriented design you would use polymorphism instead of weak typing.

Force template parameter to be a structure

I'm trying to do a base template class which parameter T must be a structure.
When I use a variable declared as being of type T (both in the template class as in a class that extends it defining T) GCC fails to compile it:
GCC error: invalid use of incomplete
type ‘struct x'
Despite it working on VC I understand that it doesn't work because it shouldn't because the compiler isn't aware per the standard of the types that T represent.
Is there a way of making explicit that the type must be a structure?
What I'm doing in the code that works in VC is:
In the base class:
T* x
new T
sizeof(T)
In those that extend it:
x->member
Edit: I tried to take the relevant code. Here it is:
struct SomeStructureType
{
int memberA;
int memberB;
}
template <typename T> class Base
{
protected:
T* s;
void addMember(string name,void* offset);
Base()
{
s = new T;
}
};
class Extender : public Base<SomeStructureType>
{
public:
Extender()
{
addMember("memberA",&s->memberA);
}
}
Most (if not all) times the compiler complains about using an 'incomplete' type the problem resides in trying to use a forward declared class that has not been completely defined.
There are just so many things you can do with an incomplete type: define functions that take or return the type or references to it, define reference or pointer variables of that type... and others you cannot do: define variables of that type, create an object of the type, call any method or request any attribute from the type...
The question in the title can be dismissed; C++ classes and structures cannot be distinguished other than by source code inspection.
The explanation is quite confusing. There's apparently a message about struct x yet the example code contains not a single x. That tells me that you're not careful about matching up errors and source code. Once you do that, you often don't need StackOverflow anymore - you'll see the problem yourself.
There is nothing wrong with the code you've posted other than two missing semicolons after class/struct definitions: http://codepad.org/yfbHa8sO
The problem isn't related to the fact that T must be a structure. The problem is in that one of the structures (that I'm using in my code but was not created by me) is said to be incomplete by gcc. Anyway, I removed the class that uses this structure and other classes compile with the same base class. So, is up to me to fix it and what I assumed about the problem was wrong.