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

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.

Related

Is the c++ code in standard library all valid 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.

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.

How to enable completion of C++ template classes in vim using YouCompleteMe

When using the vim plugin YouCompleteMe for C++ code completion I stumbled over an issue.
Using nested template classes stops the completion to work properly.
Consider the following example to reproduce the behaviour:
#include <vector>
template<class T>
class foo {
public:
void Init();
private:
struct bar {
int foobar;
};
bar one_bar;
std::vector<foo<T>::bar> some_bars;
};
template<class T>
void foo<T>::Init(){
one_bar.foobar = 0; // completion as expected
some_bars.at(0).foobar = 0; // no completion neither for "at" nor for "foobar"
}
The code completion for "some_bars" is not working at all while "one_bar" behaves as expected.
How can I get completion working for this code? Is this issue related to the setup and should actually work or is it a bug in YCM?
My system is debian jessie/sid based, vim version 7.4, YCM latest version from GitHub.
Edit:
There are similar issues reported in YCMs bug tracker:
https://github.com/Valloric/YouCompleteMe/issues/243
https://github.com/Valloric/YouCompleteMe/issues/530
Seems to be a bug in clang rather than in YCM. Can someone confirm this?
Edit2:
I opened another issue in the YCM issue tracker.
https://github.com/Valloric/YouCompleteMe/issues/1170
The intention is to get more information on what the bug in clang exactly is and finally to make a bug report in the clang issue tracker.
Edit3:
I followed the proposed procedure from RedX and fed my code in clang to get completions.
Clang does not provide any suggestions for the discussed positions in the code.
This clearly is the reason why YCM fails to make suggestions in vim and it has nothing to do with YCM or vim.
A bug report in the clang issue tracker has been filed:
http://llvm.org/bugs/show_bug.cgi?id=20973
I think, under the rules of C++, you cannot get completion in this case.
Without knowledge of the type T, we don't know what methods std::vector<T> will have, as each instansiation of a template in C++ can have different methods.
As #Chris Jefferson mentioned above it is theoretically impossible .
This comment doesn't take in account template specializations
In the code shown here, all completions are clearly known, even without knowing the type T. It is not a std::vector but a std::vector<foo::bar>
This occurred to me in a very different context while I was trying to write a specialization for a template without deducting a template.I will provide my example to make the situation clear. So lets say you have an enumerator and you have a meta_info class that defines a size for an enumerator it takes by template so :
enum class e{a,b};
template <class Enum>
struct meta_info;
template<>
meta_info<e>{
static constexpr size_t s=2;
}
Ok this works and it is nice to have but what happens if you try to do the same thing in an enumerator nested in a template class?
template <class Tag>
struct str{
enum class e{a,b};
}
template <class Enum>
struct meta_info;
template<T>
meta_info<str<T>::e>{
static constexpr size_t s=2;
}
This doesn't compile as someone else(another part of the code) might change e with another specialization.There is no formal way for a compiler to know if a specialization changes a type even at the first passes of compilation. Having in mind that auto-complete tools most of the times just use the includes paths to find a suggestion this would be impossible. So in the future I would like to see in ycm something like an informal instantiation like VS has done

How to identify missing typename in Visual Studio [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 10 years ago.
Is there anyway to identify missing typename in VS ? Does VS at least produce some kind of warning ?
template<class T>
void dum() {
std::vector<T> dum_vector;
typename std::vector<T>::iterator it = dum_vector.begin();
// VS compiles it with or without typename, but I would like to know whether
// I forgot to put a typename, since without typename the code may not compile
// with another compiler (e.g. GCC)
}
I'm not sure if it has 100% standard conformance, but MSVC produces Compiler Warning (level 1) C4346 for all or most cases in which typename was explicitly needed. So as long as you are compiling with compiler flag /W1 or greater you should be okay.
Actually in the current version of C++ (which is C++11), you don't need to write that much. You just could write this:
auto it = dum_vector.begin();
and you're done.
Note that auto is supported since MSVC10, so if you're using it, I would recommend you to use auto in place of blah::blah::iterator. If you're using older version, it is better to upgrade and avail benefits of C++11 features as much as possible. If you cannot do that, then it is very unlikely that MSVS can tell you the missing typename, given that the compiler compiles the non-Standard code in the first place!

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.