简体   繁体   中英

c++ How does compiler know that a parameter is an STL container?

c++ newbie question - How can the C++ compiler know that the parameter to a template function has has STL methods as members? in C# you tell a generic method that a parameter has a type constraint, most commonly. it must implement an interface, but with c++ templates there is no restriction on the parameter type.

#include <list>
#include <iostream>
using namespace std;
template <typename T>
void DisplayContents (const T& Input)
{
    for (auto iElement = Input.cbegin() // no intellisense
    ; iElement != Input.cend()
    ; ++ iElement )
    cout << *iElement << ' ';

    cout << endl;
}
int main ()
{
    std::list <int> listIntegers;
    listIntegers.push_front (10);
    listIntegers.push_front (2011);
    listIntegers.push_back (-1);
    listIntegers.push_back (9999);
    DisplayContents(listIntegers);
    //  DisplayContents(99); // neither of these will compile
    //  DisplayContents(new string("")); //
return 0;
}

so, in the templated method DisplayContents<>(const T& Input) , there is no intellisense on Input. When you type the period character, no suggestions pop up (which isn't that suprising since the function parameter hasn't specified that the input must be a list or any other type of STL container).

However, if you try and send something that isn't an STL container into DisplayContents<>(const T& Input), then the compiler throws these errors:-

  • error C2100: illegal indirection
  • error C2228: left of '.cbegin' must have class/struct/union
  • error C3536: 'iElement': cannot be used before it is initialized

suggesting that the compiler does know something about the type of the parameter needing to have some basic characteristics.

Can anyone please explain how the compiler "knows" that cbegin() and * operator can be used when a list is sent as the parameter, but not when a string or an int is sent, when apparently the type isn't known as intellisense isn't picking up the method cbegin() ?

It's quite simple, really. The compiler will pretend that T is the type of argument you passed in and then proceed with compilation. If it runs into any errors then it will report those. As long as the type of argument you use would work if you hard-coded that type then it will work.

In your case, it fails with int because an int has no cbegin() method.

It fails with new std::string("") because the argument type becomes std::string * const & , and you can't call .cbegin() on this pointer. (You would have to call ->cbegin() instead.)

However, you can call it with std::string("") (note the lack of new ) which will cause the argument to be const std::string & , and this will compile.

So it has nothing at all to do with the compiler "knowing that T represents a standard container." If you create a simple type with cbegin() and cend() methods and make sure that the return values from those methods can be incremented, dereferenced, and compared for equality, that type would work just as well.

( Here is a demo of your template function working with a user-defined type.)

Template used to make generic code.

And here the compiler will generate three overload functions for you.

void DisplayContents (const std::list<int>& Input)
void DisplayContents (const int& Input)
void DisplayContents (string* const & Input)

obviously version 2 and 3 won't compile, type const int& and string* const& does not have method cbegin() nor cend()

PS: version 3 param should be string* const& Input , thanks to cdhowie

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM