I've read related questions like this and this, and other pages, but they don't really answer my question.
Basically, I see code like the following.
class SOME_MACRO SomeClass{
SomeClass();
~SomeClass();
};
This is really confusing to me. Now I consider myself reasonably knowledgeable about C++ (though less so with the preprocessor), but I don't remember seeing declarations like that in any book I've read. However I see code like this in the real world all the time, for example in OpenCV. There seems to be a discrepancy between the C++ you learn about in a book or in class, and the C++ you actually see in practice, and I find that rather unfortunate.
I've learnt from here and here that macros like that above are used to tell the linker how to link it properly, or something like that. For the example here, the QuickFAST_Export
gets turned into either __declspec(dllexport)
or __declspec(dllimport)
. In other cases, these macros tell the linker how to behave depending on whether the system is Linux or Windows. I know all this from an abstract perspective; I know what the macros are there for and I know what they do now, roughly at least. So I don't want answers like "those macros are there so you can change the [...]", because those answers don't tell me how I might go about using this kind of declaration myself, in a program that I might write from scratch, myself.
My question is, since when was it legal to just put something like __declspec(dllimport)
in the middle of a class declaration anyway? What actual thing is __declspec(dllimport)
? An int
? An object? In which part of the C++ standard does it say that class declarations like this are legal? If someone could write a minimal program illustrating a class declaration with a non-trivial (non-empty) macro in the middle of it, that compiles and preferably does something visible, that would be much appreciated.
I've learnt from here and here that macros like that above are used to tell the linker how to link it properly, or something like that.
To be pedantic, it's not the macro that tells the linker how to link. The macro is simply replaced by the preprocessor by whatever text it's defined to be replaced with. In the case of your example, it would be conditionally replaced with __declspec(dllexport)
or __declspec(dllimport)
. Those declspec specifiers on the other hand do tell the linker what to do... at least some linker that understands the specifier.
since when was it legal to just put something like __declspec(dllimport) in the middle of a class declaration anyway?
Since Microsoft implemented their compiler and specified that it's legal. It's not legal according to the c++ standard.
In which part of the C++ standard does it say that class declarations like this are legal?
It doesn't. Using those specifiers is non-standard and not guaranteed to work in any other compiler than Microsoft's. That's why such macro is typically defined to expand to an empty string (or possibly something else, specific to another implementation) when used in a compiler that does not support the keyword.
What actual thing is __declspec(dllimport)?
It is a non-standard keyword. You can find out more from their (Microsoft) documentation.
To dive a little bit deeper, the keywords tell the linker how to export symbols when compiling a shared (dynamically linked) library. Dynamic linking is a concept that's entirely foreign to the standard. It's implementation defined.
how I might go about using this kind of declaration myself, in a program that I might write from scratch, myself.
Do you intend to write a shared library? If not, then you don't need to know. If yes, then you need to read the documentation of every platform that you're targetting.
Here is a walkthrough in the Microsoft's documentation that guides you through the steps to create a dynamically linked library.
The spec doesn't specify how to link a program together or to external libraries, or building libraries, or frankly anything to do with the linker other than which symbols are visible across translation units.
The implementation is free to, and responsible for, implementing all that how they want, even through language extension. Anything with two underscores is implementation assigned. So everything about what's going on there is legal, and you'll not find it anywhere in the spec.
For identifiers adjacent underscores (e.g. __attribute__
or __declspec
) and a leading underscore followed by an upper case character (e.g. _Bool
or _Thread_local
) are (generally) reserved for future use and use by the compiler. That means that the normal language rules don't apply for your example as the compiler is free to extend the language. (C.f. "What are the rules about using an underscore in a C++ identifier?")
Have a look at the huge list of language extensions of GCC: https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions
And the input is really only parsed after the preprocessing. SOME_MACRO
also could contain X; class
for all good it would do.
__declspec(dllimport)
There are multiple types of attributes and specifiers that you can set based on what you are doing, what compiler you are using, what operating system you're targeting, ext. What most people learn is not targeted at a specific compiler but the core C++/C standards which everyone supports.