Ahmad Jamal Mughal
Ahmad Jamal Mughal

Reputation: 89

Stack Template Arguments

Focus on the template arguments

I can create a stack (an adapter class template from standard library) object like this,

stack<int, vector<int>> myStack;

I know the second template argument means the underlying data structure of the stack. But why the following line doesn't give a compile time error?

stack<int, vector<string>> myStack;

Notice that I'm declaring a stack to contain elements of type int, but at the same time I'm declaring the underlying data structure to hold string elements.

Functionally, It works as if it was a stack of string elements.

Upvotes: 4

Views: 198

Answers (3)

nshct
nshct

Reputation: 1230

What you are doing is undefined behaviour. Nevertheless, I am going to explain why it seems to work fine.

The container adapter std::stack<T, TContainer> contains several type symbols that are aliases for types that will be commonly used. There is a list here.

One that concerns us here is std::stack::value_type. It basically determines what type the methods std::stack::push and friends expect:

void push( const value_type& value );

We can also see how it is defined:

using value_type = typename TContainer::value_type

So, the type that is used in all actions is actually only based on the second type, TContainer ! In your case, that is vector<string>::value_type, so value_type will be an alias to string. The type used for T, int in your case, is not used. Thus, everything seems to work.

But even though this works in your case with your particular compiler, it is actually not allowed:

The behavior is undefined if T is not the same type as Container::value_type. (since C++17)

You can find the source for this quote here.

Upvotes: 6

Bill Lynch
Bill Lynch

Reputation: 81936

If I had to guess, I would imagine that your implementation is discarding the int template argument, and just uses Container::value_type instead.

Once we get to C++17, this will be explicitly illegal. Some compilers will already not appreciate this code..

For example:

#include <stack>
#include <string>
#include <vector>

int main() {
    std::stack<int, std::vector<std::string>> s;
    s.push(3);
}

Fails to compile under OS X (clang, libc++, c++11) with:

blah.cc:7:7: error: no matching member function for call to 'push'
    s.push(3);
    ~~^~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/stack:194:10: note: 
      candidate function not viable: no known conversion from 'int' to 'const value_type' (aka
      'const std::__1::basic_string<char>') for 1st argument
    void push(const value_type& __v) {c.push_back(__v);}
         ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/stack:197:10: note: 
      candidate function not viable: no known conversion from 'int' to 'value_type' (aka 'std::__1::basic_string<char>') for
      1st argument
    void push(value_type&& __v) {c.push_back(_VSTD::move(__v));}
         ^
1 error generated.

Upvotes: 0

1stCLord
1stCLord

Reputation: 880

From the documentation:

T - The type of the stored elements. The behavior is undefined if T is not the same type as Container::value_type. (since C++17)

Undefined behaviour means it might compile, it might even work, or it might wipe your hard drive.

How it fails, if it does, is implementation dependant.

Upvotes: 1

Related Questions