Reputation: 89
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
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
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
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