How to know if a type is a specialization of std::vector?
In C++11 you can also do it in a more generic way:
#include <type_traits>
#include <iostream>
#include <vector>
#include <list>
template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};
template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
int main()
{
typedef std::vector<int> vec;
typedef int not_vec;
std::cout << is_specialization<vec, std::vector>::value << is_specialization<not_vec, std::vector>::value;
typedef std::list<int> lst;
typedef int not_lst;
std::cout << is_specialization<lst, std::list>::value << is_specialization<not_lst, std::list>::value;
}
How can I check if template type is any type of std::vector
You can use partial specialization:
#include <type_traits>
#include <iostream>
#include <vector>
template <typename C> struct is_vector : std::false_type {};
template <typename T,typename A> struct is_vector< std::vector<T,A> > : std::true_type {};
template <typename C> inline constexpr bool is_vector_v = is_vector<C>::value;
int main() {
std::cout << is_vector_v< std::vector<int> > << "\n";
std::cout << is_vector_v< int > << "\n";
}
Detect whether a type is a vector of enum
Specializations are allowed to have a different number of template parameters than the primary. In fact, this happens quite often. However, as the error indicates, you are not allowed to give any of them default arguments.
That aside, I prefer simplicity, when possible.
template <typename T>
struct is_vector_enum : std::false_type { };
template <typename T>
struct is_vector_enum<std::vector<T>> : std::is_enum<T> { };
How to check if there is a specialization for std::less, using concepts?
Any type that is less-than comparable is comparable with std::less
. That is, the primary std::less
template will invoke operator<
for any T
it is given. You can provide an explicit specialization for some user-defined type, but you don't have to if your type is operator<
comparable.
std::complex
is not less-than comparable by nature. However, you're not allowed to provide specializations for a standard library template if the all of the template parameters for the specialization are themselves standard-library types. Trying to do so achieves UB, so you could get any result.
But in any case, std::hash
is something you must provide a specialization for. That's part of what it means to make a type "hashable".
These are two different designs for different kinds of functionality. A type can implicitly be less-than comparable, but a type cannot implicitly be hashable.
And no, there is no way to detect with a concept whether a particular template instantiation comes from a primary template or a specialization.
If what you're trying to do is see if a type is less-than comparable, you shouldn't be relying on std::less
at all. Instead, you should be using the std::totally_ordered
concept.
Check if class is a template specialization
C++20 is a weird, weird world. Cross-checking is welcome as I'm a beginner with CTAD and not entirely sure I've covered all bases.
This solution uses SFINAE to check whether class template argument deduction (CTAD) succeeds between the requested class template and the mystery type. An additional is_same
check is performed to prevent against unwanted conversions.
template <auto f>
struct is_specialization_of {
private:
template <class T>
static auto value_impl(int) -> std::is_same<T, decltype(f.template operator()<T>())>;
template <class T>
static auto value_impl(...) -> std::false_type;
public:
template <class T>
static constexpr bool value = decltype(value_impl<T>(0))::value;
};
// To replace std::declval which yields T&&
template <class T>
T declrval();
#define is_specialization_of(...) \
is_specialization_of<[]<class T>() -> decltype(__VA_ARGS__(declrval<T>())) { }>::value
// Usage
static_assert(is_specialization_of(std::array)<std::array<int, 4>>);
First caveat: Since we can't declare a parameter for the class template in any way without knowing its arguments, passing it around to where CTAD will be performed can only be done by jumping through some hoops. C++20 constexpr and template-friendly lambdas help a lot here, but the syntax is a mouthful, hence the helper macro.
Second caveat: this only works with movable types, as CTAD only works on object declarations, not reference declarations. Maybe a future proposal will allow things such as std::array &arr = t;
, and then this will be fixed!
Actually fixed by remembering that C++17 has guaranteed copy-elision, which allows direct-initialization from a non-movable rvalue as is the case here!
Check if class is a template specialization?
Here's one where you can provide the template to be matched against :
template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};
template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};
static_assert(is_specialization<std::vector<int>, std::vector>{}, "");
static_assert(!is_specialization<std::vector<int>, std::list>{}, "");
Partial specialization for std::vector of all types
You're almost there, all you need is the syntax.
// SPECIAL CASE with vector of vectors
template < typename element_type >
class Container<std::vector< element_type >>
You could also extract the allocator type from vector
, if you actually want to support different allocators.
I'm not sure whether I'm going too far with templateization
If you have a choice between writing a template or not, usually you shouldn't. Otherwise, nothing here is suspicious.
Specialization of class for vectors of specific type_trait
The problem is, that std::hash
has only a single template parameter and you cannot add an additional defaulted template parameter in a partial specialization. So you have several choices, depending on what you want to do with your hash.
Please also rethink your approach. This comment by Yakk is very useful:
You may not specialize templates in std unless the specialization depends on a user-provided type. – Yakk
You can easily fix thisby not putting your own hash
into the std
namespace.
You could simply remove the
enable_if
from the template argument list and replace it with astatic_assert(std::is_arithmetic<dtype>::value, "!");
in the struct body, given that you only ever want to hash vectors of arithmetic type.
SFINAE on the call operator. This way, you have to provide all the hash methods for all other vector types within the same struct. Also you have to go through some funny business of repeating the template parameter to make the compiler happy. It's very important that your SFINAE criteria are mutually exclusive, otherwise you'll get horrible errors.
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
namespace std {
template< typename dtype >
struct hash< std::vector<dtype> >
{
template< typename T = dtype >
std::enable_if_t<std::is_arithmetic<T>::value, size_t>
operator()(const std::vector<T> &input) const
{
constexpr size_t FNV_prime = 1099511628211ul;
constexpr size_t FNV_offset = 14695981039346656037ul;
size_t hashed = FNV_offset;
for(const auto &n:input)
{
hashed ^= n;
hashed *= FNV_prime;
}
return hashed;
}
template< typename T = dtype >
std::enable_if_t<!std::is_arithmetic<T>::value, size_t>
operator()(const std::vector<T> &input) const
{
std::cout << "No hash for you :-(\n";
return 0;
}
};
} // namespace std
int main() {
{
std::vector<int> v{1,2,3,4};
size_t hash = std::hash<std::vector<int>>{}(v);
std::cout << hash << "\n";
}
{
std::vector<std::string> v{"Hello", "world!"};
size_t hash = std::hash<std::vector<std::string>>{}(v);
std::cout << hash << "\n";
}
}Live example
You can also declare your own struct for hashing and add as many template parameters as you want. Then you just need
std::hash
to inherit from your custom struct.#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
template < typename T, bool = std::is_arithmetic<T>::value >
struct vector_hash;
template < typename T>
struct vector_hash<T,true> {
size_t operator()(std::vector<T> const &input) const
{
constexpr size_t FNV_prime = 1099511628211ul;
constexpr size_t FNV_offset = 14695981039346656037ul;
size_t hashed = FNV_offset;
for(const auto &n:input)
{
hashed ^= n;
hashed *= FNV_prime;
}
return hashed;
}
};
template < typename T>
struct vector_hash<T,false> {
size_t operator()(std::vector<T> const &) const
{
std::cout << "No hash for you :-(\n";
return 0;
}
};
namespace std {
template< typename dtype >
struct hash< std::vector<dtype> > : vector_hash<dtype> {};
} // namespace std
int main() {
{
std::vector<int> v{1,2,3,4};
size_t hash = std::hash<std::vector<int>>{}(v);
std::cout << hash << "\n";
}
{
std::vector<std::string> v{"Hello", "world!"};
size_t hash = std::hash<std::vector<std::string>>{}(v);
std::cout << hash << "\n";
}
}Live example
Specialize template function to return vector
You can't partially specialize functions. You can overload them though, but the way of doing it is not obvious, since your function doesn't take any parameters.
First, you need a way to check if a type is a std::vector<??>
:
template <typename T> struct IsVector : std::false_type {};
template <typename ...P> struct IsVector<std::vector<P...>> : std::true_type {};
Then you can plug it into requires
:
template <typename T>
T Read()
{
// Generic overload
}
template <typename T> requires IsVector<T>::value
T Read()
{
// Vector overload
}
Alternatively, you could have a single function, with if constexpr (IsVector<T>::value)
inside.
Template class specialization for vector type - different valid syntax?
Given the definition of the class template,
template<> // <--- optional?
template<typename T>
struct PrintMe<std::vector<T>> { ... };
is not valid.
You need to remove that line and use:
template<typename T>
struct PrintMe<std::vector<T>> { ... };
Related Topics
Does Resizing a Vector Invalidate Iterators
Write and Read String to Binary File C++
Catching "Stack Overflow" Exceptions in Recursive C++ Functions
How to Use C++ Preprocessor Stringification on Variadic MACro Arguments
C++11 "Overloaded Lambda" with Variadic Template and Variable Capture
How to Use Dynamic Name for Variables in C++
Setting Roi with Mouse from a Rectangle on a Video
What Operators Do I Have to Overload to See All Operations When Passing an Object to a Function
Do All Virtual Functions Need to Be Implemented in Derived Classes
How to Enable Experimental C++11 Concurrency Features in Mingw
If Temporaries Are Implicitly Non-Modifiable, How Does This Work
What Is the Meaning of Auto When Using C++ Trailing Return Type
How to Check If Window Is "Always on Top"
Qt3D. Draw Transparent Qspheremesh Over Triangles
Overload Operators as Member Function or Non-Member (Friend) Function
Possible Causes for Boost Not Being Found by Cmake in Certain Situations