This question already has answers here:
Why function template cannot be partially specialized?
(4 answers)
C++ function template partial specialization?
(7 answers)
Closed 25 days ago.
I have a template function and a partial specialized version of it like this:
template<typename _T>
int values_in_range(const _T &beg, const _T &end) {
throw std::runtime_error("unsupoorted data type");
}
template<>
int values_in_range<int>(const int &beg, const int &end) {
return end - beg;
}
These code works good and then I want to extend the capabilities of the function to a template class that have two template parameters like this:
template<typename _Ty, size_t _Dims>
class vec {
// ...
};
How to partial specialize the function values_in_range for class vec with keeping the parameter _Dims unspecialized?
I try following code but encount error:
template<size_t _Dims>
int values_in_range<vec<int, _Dims>>(const vec<int, _Dims> &beg,
const vec<int, _Dims> &end) { // <-- compiling error
int ret = 0;
for (int i = 0; i < _Dims; ++i) {
//some computing here
}
return ret;
}
The error message:
error: non-class, non-variable partial specialization ‘values_in_range<vec<int, _Dims> >’ is not allowed
[build] 349 | int values_in_range<vec<int, _Dims>>(const vec<int, _Dims> &beg,
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There is no partial specialization of function templates. Your first snippet of code is no partial specialization. You can partially specialize class templates. A function template can usually be refactored to a class template with operator().
template<typename _T>
struct values_in_range {
int operator()(const _T &beg, const _T &end) const {
throw 42;
}
};
template<>
struct values_in_range<int> {
int operator()(const int &beg, const int &end) const {
return end - beg;
}
};
template<typename _Ty, unsigned _Dims>
class vec {};
template<unsigned _Dims>
struct values_in_range<vec<int,_Dims>> {
int operator()(const vec<int, _Dims> &beg, const vec<int, _Dims> &end) const {
int ret = 0;
for (int i = 0; i < _Dims; ++i) {
//some computing here
}
return ret;
}
};
Related
I'm working on a C++11 wrapper around a C api. The C api offers a bunch of getters for various types, with a different name for each type. Values are retrieved by array of a given size, known at compilation.
I want to give the type and the array size by template, to call the right function.
#include <string>
#include <iostream>
template <typename T>
struct make_stop {
constexpr static bool value = false;
};
class Foo
{
public:
Foo() : i(42) {}
template<typename T, size_t n>
T get();
private:
int i = 0;
};
template<typename T, size_t n>
T Foo::get() { static_assert(make_stop<T>::value); return T(); }
template<int, size_t n>
int Foo::get() { return i + n; }
int main() {
Foo foo;
int i = foo.get<int, 4>();
double f = foo.get<double, 2>();
return 0;
}
But it fails to match the right function
main.cpp:26:5: error: no declaration matches 'int Foo::get()'
int Foo::get() { return i + n; }
^~~
main.cpp:15:7: note: candidate is: 'template<class T, long unsigned int n> T Foo::get()'
T get();
its a bit vauge from your question, but assuming you are wanting to index into some c- arrays and return the value at I you can't specialize function templates like you want, but you can use some tags instead, something like..
class Foo
{
public:
Foo() : is{1,2,3,4,5,6,7,8,9,10},ds{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.1} {}
template <typename T> struct type_c{};
template <size_t I> struct int_c{};
template<typename T,size_t I>
auto get()
{ return get_impl(type_c<T>(),int_c<I>()); }
private:
template <size_t I>
auto get_impl(type_c<int>,int_c<I>)
{ return is[I]; }
template <size_t I>
auto get_impl(type_c<double>,int_c<I>)
{ return ds[I]; }
int is[10];
double ds[10];
};
int main() {
Foo foo;
int i = foo.get<int,0>();
double d = foo.get<double,2>();
std::cout << i << " " << d << std::endl;
return 0;
}
Demo
If I understood you correctly you want to partially specialize get for T. Unfortunately partial specialization for methods is not allowed by the standard. You can however get around this with a static method on a class templated by T and specializing the class.
Like this:
template <class T> struct Foo_helper;
struct Foo
{
Foo() : i{42} {}
template<class T, std::size_t N>
T get()
{
return Foo_helper<T>::template get<N>(*this);
}
int i = 0;
};
template <class T> struct Foo_helper {};
// specialize Foo_helper for each type T you wish to support:
template <> struct Foo_helper<int>
{
template <std::size_t N>
static int get(const Foo& foo) { return foo.i + N; }
};
template <> struct Foo_helper<double>
{
template <std::size_t N>
static double get(const Foo& foo) { return foo.i + N; }
};
int main()
{
Foo foo{};
int i = foo.get<int, 4>();
double d = foo.get<double, 2>();
}
The following code compiles with gcc (g++) but complains with clang (c++).
I was expecting the line n1::generic(*it); to look for a my_traits<bool> (or my_traits<const bool>) specialization but, it seems to be looking for the name specific within the vector (const?) from within that same specialization.
Also, this is specific to bool. Other types like int work fine. (I tried adding a my_traits<vector<bool> > (and also const bool) specialization but it didn't help).
#include <vector>
namespace n1 {
template <class T> struct my_traits { };
template <> struct my_traits<bool> {
static void specific(bool b) { }
};
template <> struct my_traits<int> {
static void specific(int b) { }
};
template <typename T> void generic(const T& t)
{
my_traits<T>::specific(t);
}
template <typename T> struct my_traits<std::vector<T> > {
static void specific(const std::vector<T>& b)
{
if (! b.empty()) {
for (typename std::vector<T>::const_iterator it = b.begin();
it != b.end(); ++it) {
n1::generic(*it);
}
}
}
};
}
namespace n2 {
struct ArrayOfBoolean {
std::vector<bool> values;
};
struct ArrayOfInt {
std::vector<int> values;
};
}
namespace n1 {
template<> struct my_traits<n2::ArrayOfBoolean> {
static void specific(const n2::ArrayOfBoolean& v) {
n1::generic(v.values);
}
};
template<> struct my_traits<n2::ArrayOfInt> {
static void specific(const n2::ArrayOfInt& v) {
n1::generic(v.values);
}
};
}
c++ codec.cc -o codec
In file included from codec.cc:1:./codec.h:17:23: error: no member named 'specific' in 'n1::my_traits<std::__1::__bit_const_reference<std::__1::vector<bool,std::__1::allocator<bool> > > >'
my_traits<T>::specific(t);
~~~~~~~~~~~~~~^
./codec.h:26:25: note: in instantiation of function template specialization 'n1::generic<std::__1::__bit_const_reference<std::__1::vector<bool, std::__1::allocator<bool> > > >' requested here
n1::generic(*it);
^
./codec.h:17:23: note: in instantiation of member function 'n1::my_traits<std::__1::vector<bool, std::__1::allocator<bool> > >::specific' requested here
my_traits<T>::specific(t);
^
./codec.h:47:17: note: in instantiation of function template specialization 'n1::generic<std::__1::vector<bool, std::__1::allocator<bool> > >' requested here
n1::generic(v.values);
^
1 error generated.
Odd as it seems, a vector<bool> doesn't hold any bools. Only bits which you cannot get a real reference to.
So in n1::generic(*it); there is no const bool&, only a __bit_const_reference proxy class.
I have a template:
template <typename T, int size>
class Array
{
T A[size];
public:
T& operator[](int index) ;
};
template <typename T, int size>
T& Array<T,size>::operator[](int index)
{
if (index>=size || index<0)
return A[0];
else
return A[index];
}
And its specialisation class:
typedef struct Data
{
int id;
char name[10];
double temp;
double quantity;
}Data;
template <>
class Array<Data, int>
{
};
And I try to use it:
int main()
{
Array<Data, int> tab;
return 0;
}
But I'm getting this error, and dont really know why:
error: type/value mismatch at argument 2 in template parameter list
for ‘template class Array’|
What's wrong?
Its strange. I changed the code to the following one:
template <>
class Array<Data, 20>
{
};
int main()
{
Array<Data, 20> tab;
return 0;
}
And its ok now. Thanks!
I can only guess that what you actually want to create a template specialization for Array<T, size> where T=Data and size is not specified.
template <int size>
class Array<Data, size> // partial specialization
{
};
When you instantiate the template, you have to specify a constant size:
int main()
{
Array<Data, 5> tab; // size=5 for this example
return 0;
}
I have this simple code below, a template with 2 type parameters. If I declare my class with the same type (like BidirectionalMap<int,int>), I receive an error:
int BidirectionalMap<T,S>::operator [](T) const' : member function already defined or declared
Here's my template code:
template <class T, class S>
class BidirectionalMap{
int count(T t){
return 1;
}
int count(S s){
return 1;
}
};
The error you got is normal, because after substitution you have
template <>
class BidirectionalMap<int, int>
{
int count(int t){ return 1; }
int count(int s){ return 1; } // Duplicated method
};
To solve that, you may provide partial specialization:
template <class T>
class BidirectionalMap<T, T>
{
int count(T t) { return 1; }
};
In C++20, you might use requires to "discard" methods:
template <class T, class S>
class BidirectionalMap
{
int count(T t) requires(!std::is_same<T, S>::value) { /*..*/ }
int count(S s) requires(!std::is_same<T, S>::value) { /*..*/ }
int count(T t) requires( std::is_same<T, S>::value) { /*..*/ }
};
I'm not getting the partial template specialization.
My class looks like this:
template<typename tVector, int A>
class DaubechiesWavelet : public AbstractWavelet<tVector> { // line 14
public:
static inline const tVector waveletCoeff() {
tVector result( 2*A );
tVector sc = scalingCoeff();
for(int i = 0; i < 2*A; ++i) {
result(i) = pow(-1, i) * sc(2*A - 1 - i);
}
return result;
}
static inline const tVector& scalingCoeff();
};
template<typename tVector>
inline const tVector& DaubechiesWavelet<tVector, 1>::scalingCoeff() { // line 30
return tVector({ 1, 1 });
}
The error gcc outputs is:
line 30: error: invalid use of incomplete type ‘class numerics::wavelets::DaubechiesWavelet<tVector, 1>’
line 14: error: declaration of ‘class numerics::wavelets::DaubechiesWavelet<tVector, 1>’
I've tried several solutions, but none worked.
Anybody has a hint for me?
template<typename tVector>
inline const tVector& DaubechiesWavelet<tVector, 1>::scalingCoeff() { // line 30
return tVector({ 1, 1 });
}
That's a definition of a member of a partial specialization that would be defined as follows
template<typename tVector>
class DaubechiesWavelet<tVector, 1> {
/* ... */
const tVector& scalingCoeff();
/* ... */
};
It's not a specialization of the member "scalingCoeff" of the primary template "DaubechiesWavelet". Such a specialization is required to pass the value of all arguments, which your specialization does not do. To do what you want, you can use overloading though
template<typename tVector, int A>
class DaubechiesWavelet : public AbstractWavelet<tVector> { // line 14
template<typename T, int I> struct Params { };
public:
static inline const tVector waveletCoeff() {
tVector result( 2*A );
tVector sc = scalingCoeff();
for(int i = 0; i < 2*A; ++i) {
result(i) = pow(-1, i) * sc(2*A - 1 - i);
}
return result;
}
static inline const tVector& scalingCoeff() {
return scalingCoeffImpl(Params<tVector, A>());
}
private:
template<typename tVector1, int A1>
static inline const tVector& scalingCoeffImpl(Params<tVector1, A1>) {
/* generic impl ... */
}
template<typename tVector1>
static inline const tVector& scalingCoeffImpl(Params<tVector1, 1>) {
return tVector({ 1, 1 });
}
};
Notice that the initialization syntax you use will only work in C++0x.
I don't see the class specialized. You must specialize the class, and inside it, the method.