How do I get the type of the elements in a vector?
You can get the type like this:
typename std::vector<T>::value_type;
Then use static_assert
together with std::is_same
.
template <typename T1, typename T2>
void special_push_back(std::vector<T1>& v, T2 elem)
{
// check that T1 and T2 are the same before pushing elem into v
}
then
std::vector<int> v;
special_push_back(v, 3.14); // Compile time error: double is not int
If you have C++11 features, you can also use decltype
keyword to ease the access to underlying value_type
type member:
decltype(TheContainer)::value_type nVarOfType;
Here, TheContainer
might be a container of any type. For instance, a map<int, string>
, deque<float>
or any other STL container - all STL containers have value_type
type-defined. decltype
key would give the type of given object.
If I understood the comments correctly, you may also try:
template <class Container, class... Args>
void foo(Container&& c, Args&&... args) {
typedef typename Container::value_type value_type;
// use type_traits to check value_type
...
}
An improvement would be to check whether Container
has an embedded type value_type
at all:
template <class T>
struct has_value_type
{
private:
template <class U> static std::false_type test(...);
template <class U> static std::true_type test(typename U::value_type*);
public:
enum { value = decltype(test<T>(0))::value };
};
and then use std::enable_if
:
template <class Container, class... Args>
typename std::enable_if<has_value_type<Container>::value, return_type>::type
foo(Container&& c, Args&&... args) {
typedef typename Container::value_type value_type;
...
}
Similarly, you can "enable" only templates which fulfill your requirement of the value type:
template <class Container, class... Args>
typename std::enable_if<
has_value_type<Container>::value
and std::is_same<int, typename Container::value_type>::value
>::type
foo2(Container&& c, Args&&... args) {
typedef typename Container::value_type value_type;
// here value_type equals int
}
Edit:
With even more "template tricks", you can for example ensure that all types of the variadic template pack are equal and and equals the value_type of the container:
First, a helper template:
template <typename...>
struct all_of;
template <typename T>
struct all_of<T> : std::conditional<T::value == true,
std::true_type, std::false_type>::type
{};
template <typename Head, typename... Tail>
struct all_of<Head, Tail...> : std::conditional<
Head::value == true and all_of<Tail...>::value,
std::true_type,
std::false_type>::type
{};
Without any further code, you can use it already, for example as follows:
`all_of<std::is_nothrow_copy_constructible<Args>...>::value`
While the syntax may appear weird, the const expression above evaluates to true
if all types in the parameter pack Args
have the property that its copy-constructor will not throw.
Given the helper class template all_of
, we can now enable the function template foo
only if all types in the parameter pack equal the value_type
of the container:
template <class Container, class... Args>
typename std::enable_if<
has_value_type<Container>::value
and all_of<std::is_same<typename Container::value_type, Args>...>::value
>::type
foo2(Container&& c, Args&&... args) {
typedef typename Container::value_type value_type;
// here *all* types in Args are equal value_type
}