How to check whether a certain type is a complete type in a certain .cpp
?
templateclass Test{
//some fields
void(*fun
There's a rule in C++ called ODR. The very basics of this rule (from my understanding) is that something can have as many declarations as you want, but only one definition. It seems simple, but with templates and inline function, is quite easy to break it.
With templates, multiple definition is inevitable. Instantiation of the same template will happen in all translation unit that uses it. It seems against the one definition rule, but for inline and templated entities, the rule is extended. Here's a paragraph on cppreference:
There can be more than one definition in a program, as long as each definition appears in a different translation unit, of each of the following: class type, enumeration type, inline function with external linkage inline variable with external linkage (since C++17), class template, non-static function template, static data member of a class template, member function of a class template, partial template specialization, as long as all of the following is true:
each definition consists of the same sequence of tokens (typically, appears in the same header file)
name lookup from within each definition finds the same entities (after overload-resolution), except that constants with internal or no linkage may refer to different objects as long as they are not ODR-used and have the same values in every definition.
overloaded operators, including conversion, allocation, and deallocation functions refer to the same function from each
definition (unless referring to one defined within the definition)the language linkage is the same (e.g. the include file isn't inside an
extern "C"
block)the three rules above apply to every default argument used in each definition
if the definition is for a class with an implicitly-declared constructor, every translation unit where it is odr-used must call the same constructor for the base and members
if the definition is for a template, then all these requirements apply to both names at the point of definition and dependent names at the point of instantiation
If all these requirements are satisfied, the program behaves as if there is only one definition in the entire program. Otherwise, the behavior is undefined.
In short, if any function template expands to slightly different things in some translation units, you end up in the UB land. Trust me, debugging ODR violation is the worst, because your program might work for a long time, and suddenly crash when changing some compilation options, like optimisations.
In your particular case, you want to detect if a type is complete or not to change the definition of a function. Since in some places you might have a complete type and instantiate that function, you'll end up with multiple and different definition of that function.
Be careful with macros too. If some macro definition changes in only some translation and you use that macro in a template or inline function, you violate ODR, since the function won't consist of the exact same tokens.
Now, I acknowledge that other answers also are useful indeed. Detecting whether a type is complete is not entirely useless. I use it in my code. I use it to provide nice diagnostics with static_assert
, which even some implementations of the STL do (unique_ptr
destructor in GCC's STL).
This works
#include <iostream>
#include <type_traits>
using namespace std;
class Incomplete;
class Complete {};
template <typename IncompleteType, typename = std::enable_if_t<true>>
struct DetermineComplete {
static constexpr const bool value = false;
};
template <typename IncompleteType>
struct DetermineComplete<
IncompleteType,
std::enable_if_t<sizeof(IncompleteType) == sizeof(IncompleteType)>> {
static constexpr const bool value = true;
};
int main() {
cout << DetermineComplete<Complete>::value << endl;
cout << DetermineComplete<Incomplete>::value << endl;
return 0;
}
Note I like to use std::enable_if_t
for the same effect as void_t
until that is available instead of writing its implementation myself everywhere.
Note Do take a look at the other answer as well about ODR. They bring up a valid point that you should consider before using this.