Is the c++ code in standard library all valid c++? - c++

Just out of curiosity, I looked at how std::is_pointer is implemented and saw stuff like this (one of multiple overloads):
template <class _Ty>
_INLINE_VAR constexpr bool is_pointer_v<_Ty*> = true;
which if I copy and paste into my code and compile says constexpr is not valid here. What is happening?
Is it possible to implement structs like std::is_pointer and std::is_reference by us? (Not that I would, just curious so please don't come at me)
MRE with msvc 2019:
template <class _Ty>
inline constexpr bool is_pointer_v<_Ty*> = true;
int main()
{
}
--
Error: error C7568: argument list missing
after assumed function template 'is_pointer_v'

To answer the question in the title:
No, standard library code does not need to adhere to the language rules for user code. Technically it doesn't even need to be implemented in C++, but could e.g. be directly integrated into the compiler.
However, practically the standard library code is always compiled by the compiler just as user code is, so it will not use any syntax constructs that the compiler would reject for user code. It will however use compiler-specific extensions and guarantees that user code should not generally rely on. And there are also some reservations made specifically to the standard library implementation in the standard.
For example, the snippet you are showing from the standard library implementation is not valid user code, because _Ty is a reserved identifier that may not be used by user code, because it starts with an underscore followed by an uppercase letter. Such identifiers are specifically reserved to the standard library implementation. For this reason alone most standard library code will not be valid user code.

You are using a partial template specialization here. You need a complete declaration of the template to get that code to compile, like this:
template <class _Ty>
inline constexpr bool is_pointer_v = false;
template <class _Ty>
inline constexpr bool is_pointer_v<_Ty*> = true;
See here for example code
To answer your questions, the STL implementation requires specific C++ primitives that the compiler implements to support the required API. You can't have a constexpr version of the STL if the compiler does not implement it.
It's not possible to implement the complete STL without some compiler specifics code and the operating system's primitives. This is different from system to system (you can't use the STL implementation of linux on windows for example). It relies on undefined behavior, and many optimization which are known to be right for that specific compiler.
For example, you can't implement type punning (i.e converting from float* to int* and dereferencing) without UB in C++ (see here and here)
You have to rely on memcpy, but that can't be implemented without UB code (that is well defined if you write the compiler, BTW), since memcpy is accessing the memory likely not in the initial type that it's declared.
Yet, you can always copy & paste the STL code from your system and it'll always build correctly on your compiler.

Related

How to test if std::remove_cvref is defined in the standard library?

I don't see anything resembling feature test macro for it in here:
https://en.cppreference.com/w/cpp/utility/feature_test
Neither it does not seem to be mentioned in the original paper:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0550r2.pdf
Testing for __cplusplus is also not appropriate since C++20 is not yet published but this feature could already be supported.
Could feature-test macro support appear later during standardization or is this addition too small to become part of feature-test macro and thus people who want to use the standard version conditionally are bound to get back to old school manual compiler version checking?
Looking through [tab:cpp.predefined.ft], I don't see anything possibly related to it either. Presumably because this feature is deemed to minor and t is very easy to implement one yourself:
template <typename T>
struct remove_cvref :remove_cv<remove_reference_t<T>> {};
template <typename T>
using remove_cvref_t = typename remove_cvref<T>::type;
If you are just trying to write portable code, it suffices to roll out your own version. If you are genuinely try to detect the availability of this feature, you may have to resort to the "old school manual compiler version checking", unfortunately.

What SFINAE tricks can I safely use on all MSVC >= 2013?

In Qt I had the brilliant (cough, cough) idea to start defining overloads of qHash (the hashing function used for QHash, one of Qt's associative containers) for Standard Library datatypes: std::basic_string, std::shared_ptr and the like.
There could be a shortcut for this process: instead of chasing "any Standard Library type that could be used as a key in QHash" and adding a qHash overload for it, I could just define qHash automatically if the type has a std::hash specialization for it (reasonably assuming that we don't want to do more than what the Standard Library does in this process).
That is, I could implement something like this using expression SFINAE:
template<typename T>
auto qHash(const T &t) -> decltype(std::hash<T>()(t))
{
return std::hash<T>()(t);
}
Unfortunately, although Qt demands a C++11 compiler, expression SFINAE is not allowed anywhere because MSVC does not fully support it (at the time of this writing: all MSVC versions, up to and including VS15 preview 5. Anyhow, Qt must support all the way back to 2013).
Hence, the question: is there a way to do the same, in a way that
does not use expression SFINAE
is guaranteed to work on all MSVC versions >= 2013?
I was thinking a plain good ol' C++98 SFINAE construction via enable_if and the like, but other SO answers (like this one) make me think that MSVC 2013 may miscompile that too, so the result becomes unacceptable again.
I do not think you need expression SFINAE for this, something along these lines should work.
template<typename T>
typename std::hash<T>::result_type qHash(const T &t)
{
return std::hash<T>()(t);
}
Or pretty much any approach that does SFINAE on hash::result_type. Unfortunately for you, hash::result_type is deprecated in C++17, but you can still #ifdef this code for MSVC 2013.

How to debug template arguments at compile-time?

I have a piece of code that pretty much reduces down to:
template<class T> struct MyStruct; // No definition by default
template<class T> struct MyStruct<T *> { ... }; // Specialization for pointers
Now somewhere in my code, I'm getting an instantiation of MyStruct<T> that happens to be undefined (no C++0x/011, no Boost... nothing fancy, just plain C++03):
error C2027: use of undefined type 'MyStruct<T>'
The trouble is, I have no idea where this is being caused, because the code that's doing the instantiation is itself a template, and called from numerous places, with different arguments.
Is there a way to somehow figure out what T is at compile-time, so I can understand the error messages better?
(Sorry, I forgot to mention: Visual Studio 2008.)
I believe you're using MSVC++, if so, then see the output window, it might have more info printed, especially the line number along with the filename. Once you know the file and line number, you can start from there.
Output window usually prints everything, like how and with what template argument(s), a template is instantiated. Everything step by step. Those messages are very useful when debugging.
As you found yourself, enabling /WL prints more detail messages in the output window.
I know you said no C++11, but you may want to consider, since C++03 code is backwards compatible in all C++11 compliant compilers, to use the static_assert feature of C++11 to debug your code ... if you must do the final compile with a C++03 compiler, then you can always create a #define and use the #ifdef and #endif pre-processor macros to make sure that the static_assert feature does not cause problems in earlier compilers that do not support C++11 features.
See the MSDN docs here for more info.

What does ::template mean other than making TMP compile [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Using template parameters as template parameters
Here's a code snippet of some heavily templated container classes used to bind an arbitrary amount of fields of arbitrary types. A co-worker of mine found that my code didn't compile under GCC and after much research he found the fix to get it to deduce the templates correctly by adding ::template ... Neither of us had ever seen this before and still don't really know what this is other than something that GCC needs for my code that Visual Studio 2010 does not need.
template< typename T, int N >
struct SingleBindMemberStruct
{
typedef typename TGenericBindingHandler<T>::BindToUse BindType;
BindType m_Member;
template< typename ContainerClass >
static void AddBinding(CPackedTableDataSpec* spec)
{
// Perhaps with newer versions of the compilers we can find a syntax that both accept. This is with gcc-4.5 and Visual Studio 2010
#if defined(__GNUC__)
TGenericBindingHandler<T>::template AddBinding<ContainerClass>(spec, N, &ContainerClass::template SingleBindMemberStruct<T,N>::m_Member);
#else
TGenericBindingHandler<T>::template AddBinding<ContainerClass>(spec, N, &ContainerClass::SingleBindMemberStruct<T,N>::m_Member);
#endif
}
};
Does anyone know syntactically what ::template can or should be used for? If anyone has a snippet from the standard that describes it that would be perfect!
Edit:
Alright so sounds like it is really as simple as helping the compiler determine what is a template and since this is a static function we use the scope resolution operator rather than the dot operator to tell the compiler of the template. So now the only remaining question is why does Visual Studio not need this as well?
It tells the compiler that AddBinding is a template -- since the definition of AddBinding is dependent on T, the compiler wouldn't otherwise know this at the right stage of the compilation process (I'm no expert on the details, but it's to do with the C++ compilation model AFAIK). By writing template after the ::, you give the compiler information it otherwise wouldn't have. I guess more specifically, it knows that it's dealing with a template and not a < operator when it sees < after AddBinding.
If you want a more detailed answer, you might want to check out C++ Templates: The Complete Guide. (I think it's available as a PDF if you search Google.)
AddBinding is a dependent name, it isn't recognized as template during compilation. Without template it will be interpreted as function pointer and < comparison, which doesn't make sense at all.

Detect template presence at compilation time

GCC up to 4.5 doesn't have standard C++0x type trait template has_nothrow_move_constructor. I could use it in my package for optimization, but I don't want to rule out one of the common compilers and don't want to overload configuration with symbols like HAVE_STD_HAS_NOTHROW_MOVE_CONSTRUCTOR. Is it somehow possible to use that template if present and just fall back to copying if not present without using any predefined configuration symbols? I also don't want to depend on Boost, since my library is small and doesn't need Boost for any other reasons.
In pseudocode, I need something like:
template <typename type>
struct has_nothrow_move_constructor_robust
: public integral_constant <bool,
/* if possible */ has_nothrow_move_constructor <type>::value
/* otherwise */ false>
{ };
Since move constructors are only for C++0x anyway, I don't mind using other C++0x features for the above definition, if at all possible.
boost::variant has an implementation of has_nothrow_move for its own internal use - you could use that, although it's not as reliable as a proper compiler implementation would be. The source for it is here - I don't know how reliable it is, so YMMV.
Apart from that, you could test compiler version macros (__GNUC__ and __GNUC_MINOR__) to determine presence, and stub it out if not present. Unfortunately it seems has_nothrow_move_constructor isn't supported in any released version of G++ yet, so you'll have to wait a bit before you'll know the right version to use.