I'm having compile time trouble with the following code:
template <typename T,
template <class T, class Allocator = std::allocator<T> > class C>
bool is_in(const C<T>& a, const C<T>& b);
template <typename T, std::vector> // HERE
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
...
vector<int> a, b;
cout << is_in(a,b) << endl;
The error message is (on the line marked "HERE"):
error: 'std::vector' is not a type
(of course, I have included vector from std!). Any suggestion? I fiddled with it for a while, but I'm getting to the point where I could use some help :-) I need to partially specialize the initial template declaration so that I can have the compiler switch implementations depending on the actual type of the container C (there will be a is_in for sets, one for vectors, one for ranges..., with different algorithms each time).
Thanks!
The partial specialization of a function template is not allowed by the Standard.
A simple solution is : use overload.
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
This is overloaded function template. Its NOT partial specialization.
Or, you could do this:
namespace detail
{
template<typename T, typename C>
struct S
{
static bool impl(const C & a, const C & b)
{
//primary template
//...
}
}
template<typename T>
struct S<T, std::vector<T> >
{
static bool impl(const std::vector<T> & a, const std::vector<T> & b)
{
//partial specialization for std::vector
return false;
}
}
}
template <typename T, template <class T, class Allocator = std::allocator<T> > class C>
bool is_in(const C<T>& a, const C<T>& b)
{
return detail::S<T, C<T> >::impl(a,b);
}
Function template partial specialization is not allowed. In any case you're not using the template specialization syntax, you're actually writing an additional overload. Try this instead:
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
If partial specialization were allowed, it would look like this instead:
template <typename T> // std::vector is not a template parameter,
// so we wouldn't put it here
bool is_in<T, std::vector>(const std::vector<T>& a, const std::vector<T>& b)
// instead, it'd appear ^ here, when we're specializing the base template
{
return false; // implementation tbd
}
I don't know if it works (as template templates are always a trouble to my mind), but what about just trying
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
...
}
as it's a specialization.
EDIT: Others have clarified on this already, but I'll add it for completeness. The above code is actually an overload and not a partial specialization, but partial function specializations aren't allowed anyway.
Related
Suppose one has a class for which one wants to define hidden friends, e.g. heterogeneous comparison operators:
#include <concepts>
template <typename T> struct S;
template <typename C> constexpr bool is_S = false;
template <typename T> constexpr bool is_S<S<T>> = true;
template <typename T>
struct S {
using type = T;
T data;
constexpr S() : data() {}
constexpr explicit S(const T &t) : data(t) {}
template <typename U>
requires
(!is_S<U>) && std::equality_comparable_with<T, U>
friend constexpr bool operator==(const S &s, const U &u) { return s.data == u; }
};
// pre-existing, not hidden friend
template <typename T>
constexpr bool operator==(const S<T> &a, const S<T> &b) { return a.data == b.data; }
The code above seems reasonable, but it doesn't work due to CWG2369's resolution -- which at the moment is only implemented by GCC (>=11). The resolution make the constraint resolution have endless recursion, for instance when using something like this:
template <typename T>
struct wrapper
{
T value;
};
template <typename T, typename U>
requires std::equality_comparable_with <T, U>
constexpr bool operator==(const wrapper<T>& a, const wrapper<U>& b)
{
return a.value == b.value;
}
using SD = S<double>;
static_assert(std::equality_comparable<wrapper<SD>>); // ERROR, recursive constraints
The solution in this case should be to constrain S's operator== in a non-dependent way:
template <typename V, typename U>
requires
is_S<V> && (!is_S<U>) && std::equality_comparable_with<typename V::type, U>
friend constexpr bool operator==(const V &v, const U &u) { return v.data == u; }
But now this does not depend on a specific S specialization any more, and therefore will cause redefinition errors:
S<int> s1;
S<double> s2; // ERROR: redefinition of operator==
(Godbolt for all of the above.)
Am I missing something or the above solution for the recursive constraints is fundamentally incompatible with hidden friends?
Here's a possible solution: defining the operator in a non-template empty base class:
class S_base
{
template <typename V, typename U>
requires
is_S<V> && (!is_S<U>) && std::equality_comparable_with<typename V::type, U>
friend constexpr bool operator==(const V &v, const U &u) { return v.data == u; }
};
Then have S privately inherit from it:
template <typename T>
struct S : private S_base
{
using type = T;
T data;
constexpr S() : data() {}
constexpr explicit S(const T &t) : data(t) {}
};
Many thanks to Patrick Palka for suggesting this approach.
I have a template class alpha_x give as,
template <typename T,typename U>
struct alpha_x {
const T & alpha;
const Scalar<U> & x;
alpha_x(const T & a_, const Scalar<U> & x_) : alpha(a_), x(x_) {};
};
I have another class with an overload for operator =
template <typename T>
class Scalar{
...
template <typename U,typename V>
const Scalar<T> & operator = (alpha_x<U,V> c);
...
}
When we try to define this function,
template <typename T,typename U,typename V>
const Scalar<T> & Scalar<T>::operator = (alpha_x<U,V> c){
//do something...
}
Now this gives an error "Too many template parameters in template redeclaration". How do I sort this out?
T template parameter is a class Scalar's template parameter. Thus it needs to be specified in a separate template parameter list.
Following would work:
template <typename T>
template <typename U, typename V>
const Scalar<T> & Scalar<T>::operator = (alpha_x<U,V> c){
// do something...
}
I would like to define a templated structure with a friend function whose argument types are derived from types defined within the structure. The friend function should be callable without explicit type specification if the corresponding structure has been instantiated.
The following approach seems to work:
template <typename T> struct A {
typedef T const& underlying_param_type;
typedef A<T>& param_type;
friend void mutateA(param_type a, underlying_param_type b) { a.data_ = b; }
T data_;
};
If one defines the friend function with parameter types that do not depend on internals of the structure it is possible to separate interface and implementation as follows:
template <typename T> struct B;
template <typename T> void mutateB(B<T>& a, T const& b);
template <typename T> struct B {
friend void mutateB <> (B<T>& a, T const& b);
T data_;
};
template <typename T> void mutateB(B<T>& a, T const& b) { a.data_ = b; }
Now I am wondering whether both approaches can be combined. The following approach does not work (clang++ 3.3, g++ 4.8.2, -std=c++11):
template <typename T> struct C;
template <typename T> void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b);
template <typename T> struct C {
typedef T const& underlying_param_type;
typedef C<T>& param_type;
friend void mutateC <> (typename C<T>::param_type a, typename C<T>::underlying_param_type b);
T data_;
};
template <typename T> void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b) { a.data_ = b; }
int main() {
A<int> a;
mutateA(a, 1);
B<int> b;
mutateB(b, 1);
C<int> c; // error: no function template matches function template specialization 'mutateC'
mutateC(c, 1);
return 0;
}
I guess that the last approach fails since template argument deduction does not work across ::. Any ideas?
Make two little changes:
friend void mutateC ...
mutateC< int >(c, 1);
Adding a level of indirection solves the problem:
template <typename T> struct C;
template <typename T> void mutateC_impl(typename C<T>::param_type a, typename C<T>::underlying_param_type b);
template <typename T> struct C {
typedef T const& underlying_param_type;
typedef C<T>& param_type;
friend void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b) { mutateC_impl<T>(a, b); }
friend void mutateC_impl<T>(typename C<T>::param_type a, typename C<T>::underlying_param_type b);
private: T data_;
};
template <typename T> void mutateC_impl(typename C<T>::param_type a, typename C<T>::underlying_param_type b) { a.data_ = b; }
I have an indexer function, and was attempting to specialize it for the standard container types, but get errors. I'm sure it's either simple or impossible, but I can't recall which. I would prefer these as a function-object, but I wasn't able to make that work either. Is it possible to specialize a template function for a template class
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
//others are here too, but all have the same issue
}
//default indexer
template <class T>
double indexer(const T& b) { //this seems to work fine
return b.getIndex();
}
// base types
template<> double indexer<char>(const char& b) { return double(b); }
//other primitives are here too, and work fine
// standard library
template<class T, class A>
double indexer<std::vector<T,A>>(const std::vector<T,A>& b)
{ return b.empty() ? 0 : indexer(*b.cbegin()); } //line with error
error message:
error C2768: 'indexer' : illegal use of explicit template arguments
I would like for this to be specialization vs overloading, because I have a function A that takes a function object/pointer template parameter, and overloaded function A that calls the first A with a defaulted indexer.
template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>);} //default wrapper
It seems highly likely this is a duplicate question, but I cannot seem to find one.
You cannot partially specialize template functions, only template classes.
use overloading instead:
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
}
//default indexer
template <class T>
double indexer(const T& b) { return b.getIndex(); }
double indexer(const char& b) { return double(b); }
template<class T, class A>
double indexer(const std::vector<T,A>& b)
{ return b.empty() ? 0 : indexer(*b.cbegin()); }
Since functions cannot be partially specialized, I can replace the indexer functions with function objects. This seems to work fine, and solves all my problems.
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
}
template <class T>
struct indexer {
double operator()(const T& b) const
{ return b.getIndex(); }
};
template<> struct indexer<char> {
double operator()(const char& b) const
{ return double(b); }
};
template<class T, class A> struct indexer<std::vector<T,A>> {
double operator()(const std::vector<T,A>& b) const
{ return b.empty() ? 0 : indexer(*b.cbegin()); }
};
template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>());} //default wrapper
Here's a solution based solely on overloads, using C++11-style variadic templates:
template <typename T>
T print(const T & t)
{
std::cout << t << std::endl;
return t;
}
template <template <typename...> class Container, typename ...Args>
typename Container<Args...>::value_type print(const Container<Args...> & v)
{
typedef typename Container<Args...>::value_type T;
if (v.empty()) std::cout << "nil" << std::endl;
else std::cout << *v.begin() << std::endl;
return v.empty() ? T() : *v.begin();
}
If you want to be fancy and if you have access to an is_container type trait (e.g. taken from the pretty printer), you can make the container overload specific to containers, using enable_if:
template <template <typename...> class Container, typename ...Args>
typename std::enable_if<is_container<Container<Args...>>::value,
typename Container<Args...>::value_type>::type
print(const Container<Args...> & v)
{
/* ... */
}
Is there a way to find out what the return type of a function (or even better of a function pointer) is ?
I've got the following code, which breaks when I use a void function pointer, but works fine for any other return type. The error I get when using a void function pointer from gcc 4.5 is:
error: void value not ignored as it ought to be
Which makes sense. So obviously I need to check if function pointer returns something, and then obtain the result and return it.
template <class F,typename R> class Instruction
{
protected:
F (func);
R result;
public:
template <typename T>
Instruction(T const& f)
{
func = &f;
};
template <typename A> void execute(A const& a)
{
result = (func)(a);
};
template <typename A> void execute(A const& a,A const& b)
{
result = (func)(a,b);
};
template <typename A> void execute(A const& a,A const& b,A const& c)
{
result = (func)(a,b,c);
};
R get_result()
{
return result;
};
};
Normally I use a function pointer to a function which does something mostly arithmetic and I can take care of any return type at instantiation other than void functions. I've tried instantiating as:
Instruction<ptr2func2,void> foo(bar);
Instruction<ptr2func2,(*void)> foo(bar);
but in both cases it fails.
The second template argument at instantiation is used in order to define what the return type will be.
Try a template partial specialization on void:
template <class F> class Instruction<F, void>
{
protected:
F (func);
public:
template <typename T>
Instruction(T const& f)
{
func = &f;
};
template <typename A> void execute(A const& a)
{
(func)(a);
};
template <typename A> void execute(A const& a,A const& b)
{
(func)(a,b);
};
template <typename A> void execute(A const& a,A const& b,A const& c)
{
(func)(a,b,c);
};
};
You may want to use Boost::FunctionTypes which provide a metafunction able to decompose function type and give you access to the return or argument type.
In C++0x you can decltype. However, in C++03, by convention, function objects have a result_type typedef, and function pointers can have template deduction applied to them.