I am trying to create a Vector class, templated on a type T and number of elements NUM_VALUES . I want the class to use a std::vector
to store its elements when NUM_VALUES > 16384
and a std::array<T, NUM_VALUES>
to stores its elements when NUM_VALUES <= 16384.
At first I tried doing the following:
vector.h:
#include <array>
#include <vector>
#include <cstddef>
template <typename T, std::size_t NUM_VALUES, typename Elements = std::vector<T>>
class Vector
{
public:
constexpr const char* hello()
{
return "hello";
}
};
template <typename T, std::size_t NUM_VALUES>
class Vector<T, NUM_VALUES, typename std::enable_if<NUM_VALUES <= 16384, std::array<T, NUM_VALUES>>::type>
{
public:
constexpr const char* hello()
{
return "Hello";
}
};
main.cpp
#include "vector.h"
#include <iostream>
int main()
{
Vector<int, 10> vec1;
Vector<int, 1000000> vec2;
std::cout << vec1.hello() << ", " << vec2.hello();
return 0;
}
However this always selects the primary template, so I get "hello", "hello" instead of "hello", "Hello". I tried fixing this by changing vector.h to:
#include <array>
#include <vector>
#include <cstddef>
template <typename T, std::size_t NUM_VALUES, typename Elements = typename std::enable_if<16384 < NUM_VALUES, std::vector<T>>::type>
class Vector
{
public:
constexpr const char* hello()
{
return "hello";
}
};
template <typename T, std::size_t NUM_VALUES>
class Vector<T, NUM_VALUES, typename std::enable_if<NUM_VALUES <= 16384, std::array<T, NUM_VALUES>>::type>
{
public:
constexpr const char* hello()
{
return "Hello";
}
};
but got the error:
\MyVector\main.cpp(7,16): error C2146: syntax error: missing '>' before identifier 'type'
\MyVector\MyVector\main.cpp(7,2): error C2976: 'Vector': too few template arguments
\MyVector\MyVector\vector.h(9): message : see declaration of 'Vector'
\MyVector\MyVector\main.cpp(7,18): error C2146: syntax error: missing '>' before identifier 'type'
\MyVector\MyVector\main.cpp(7): error C2641: cannot deduce template arguments for 'Vector'
\MyVector\MyVector\main.cpp(7): error C2783: 'Vector<T,NUM_VALUES,Elements> Vector(void)': could not deduce template argument for 'T'
\MyVector\MyVector\vector.h(9): message : see declaration of 'Vector'
\MyVector\MyVector\main.cpp(7): error C2783: 'Vector<T,NUM_VALUES,Elements> Vector(void)': could not deduce template argument for 'NUM_VALUES'
\MyVector\MyVector\vector.h(9): message : see declaration of 'Vector'
\MyVector\MyVector\main.cpp(7,22): error C2780: 'Vector<T,NUM_VALUES,Elements> Vector(Vector<T,NUM_VALUES,Elements>)': expects 1 arguments - 0 provided
\MyVector\MyVector\vector.h(9): message : see declaration of 'Vector
I am using visual studio 2022 to compile the code.
CodePudding user response:
Type SFINAE is not part of the C standard, but you could easily accomplish the desired results in a different manner.
Define seperate templates for both alternatives. Then define an alias template Vector
that uses std::conditional_t
to detemine the type to use:
constexpr std::size_t SmallVectorMaxSize = 16384;
template <typename T, std::size_t NUM_VALUES>
class BigVector
{
public:
static_assert(NUM_VALUES > SmallVectorMaxSize);
using Elements = std::vector<T>;
constexpr const char* hello()
{
return "hello";
}
};
template <typename T, std::size_t NUM_VALUES>
class SmallVector
{
public:
static_assert(NUM_VALUES <= SmallVectorMaxSize);
using Elements = std::array<T, NUM_VALUES>;
constexpr const char* hello()
{
return "Hello";
}
};
template<class T, size_t N>
using Vector = std::conditional_t<N <= SmallVectorMaxSize, SmallVector<T, N>, BigVector<T, N>>;
int main()
{
Vector<int, 10> vec1;
Vector<int, 1000000> vec2;
std::cout << vec1.hello() << ", " << vec2.hello();
return 0;
}