Is there a way to use hidden friends when using (recursive) constraints? - c++

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.

Related

std::get like (partial) template specialization

I have class for complex numbers:
template<typename T>
struct Complex{
T r;
T i;
};
I decided to add function similar to std::get:
template<int X, typename T>
T get(const Complex<T> &a){
switch(X){
case 0: return a.r;
case 1: return a.i;
}
}
This works OK. Also I know the compiler can optimize it away.
Then I decided to rewrite it in different way:
template<int X,typename T>
T get(const Complex<T> &a);
template<typename T>
constexpr T get<0, T>(const Complex<T> &a){
return a.r;
}
template<typename T>
constexpr T get<1, T>(const Complex<T> &a){
return a.i;
}
However this does not compile and I am curious how correct implementation will be?
I tried to check how std::get is made, but I was unable to find anything that was "readable".
In C++11 you can implement this exercise like:
#include <type_traits>
template<typename T>
struct Complex{
T r;
T i;
};
template<int X, typename T>
constexpr typename std::enable_if<X == 0,T>::type
get(const Complex<T> &a){
return a.r;
}
template<int X, typename T>
constexpr typename std::enable_if<X == 1,T>::type
get(const Complex<T> &a){
return a.i;
}
Live demo
Partial template specialization is applicable for
class templates, not function templates.
In C++14 you can write trivially more concise code using std::enable_if_t.
And in C++17 you may use if constexpr to write a single function template instead of
SFINAE overloads.
Function templates cannot be partially specialised.
Another method is tag dispatching that achieves a similar effect using function overloading:
template<int X>
using Int = std::integral_constant<int, X>;
template<typename T> inline T get(const Complex<T> &a, Int<0>) { return a.r; }
template<typename T> inline T get(const Complex<T> &a, Int<1>) { return a.i; }
template<int X, typename T>
inline T get(const Complex<T> &a) { return get(a, Int<X>{}); }
I was able to come up with this, but it looks very complex for such an easy task:
namespace complex_impl__{
template<int X, typename T>
struct GetHelper{
static T get(const Complex<T> &a);
};
template<typename T>
struct GetHelper<0, T>{
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<typename T>
struct GetHelper<1, T>{
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I, T>::get(a);
}
Then I was able to move T into get() method, so I can make less code:
namespace complex_impl__{
template<int I>
struct GetHelper{
template<typename T>
static T get(const Complex<T> &a);
};
template<>
struct GetHelper<0>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<>
struct GetHelper<1>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I>::get(a);
}
One may "strip" entire template<int I> struct GetHelper class:
namespace complex_impl__{
template<int I>
struct GetHelper;
template<>
struct GetHelper<0>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<>
struct GetHelper<1>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I>::get(a);
}
The problem is that you can't partially specialise function templates. Please read
C++ template specialisation of function and Getting “illegal use of explicit template arguments” when doing a pointer partial specialization for a class method, which Nick describes the same solution of.
To get the template specialisation to work, please see Nick's answer.
Your solution does seem fine though,
I would just change the switch into an if constexpr.
#include <iostream>
template<typename T>
struct Complex
{
T r;
T i;
};
template<int X, typename T>
constexpr T get(const Complex<T> &a)
{
if constexpr(X == 0)
{
return a.r;
}
else if constexpr (X == 1)
{
return a.i;
}
}
int main()
{
Complex<int> test;
test.r = 1;
test.i = 12;
std::cout << get<0>(test) << std::endl;
std::cout << get<1>(test) << std::endl;
std::cin.get();
}

Avoiding compiling certain lines based on template operator existence

I'm currently creating a template container class in which I like to have a sorting ability whenever the template class has the comparison operator.
With SFINAE I can determine if the operator exist during runtime. However, when compiling the code below it of course still tries to compile the line containing sort, which will return compiler errors if the compare operator is not specified for that class.
Is there a way to 'avoid' compiling that line if the comparison operator doesn't exist? Not knowing the naming of such procedure, something like an '#ifdef SFINAE'?
template <class UseClass> class Container {
public:
bool Sort(void) {
if (CHECK::opCompareExists<UseClass>::value) {
sort(m_classlist.begin(),m_classlist.end()); //compile error, of course
return true;
}
return false;
}
private:
vector<UseClass> m_classlist;
};
Maybe I shouldn't use SFINAE at all... maybe it should be a template specification? How would that work (based on automatic detection that the operator is not present)?
std::sort() by default uses the less-than operator (operator<()) to compare elements so you can simply use expression SFINAE to rule out a specific overload if the type doesn't have it:
template<typename T = UseClass>
auto Sort() -> decltype(std::declval<T>() < std::declval<T>(), bool())
{
return true;
}
If substitution fails (SomeClass does not have operator<()) then compilation will fail.
If this wasn't your intention, and instead you wanted to return true if it could sort and false otherwise, then you need a trait class that you can overload based on:
namespace detail
{
template<typename T>
auto has_less_than_impl(int)
-> decltype(std::declval<T>() < std::declval<T>(), std::true_type());
template<typename>
std::false_type has_less_than_impl(...);
}
template<typename T>
struct has_less_than : decltype(detail::has_less_than_impl<T>(0)) { };
template <class UseClass> class Container
{
public:
bool Sort() { return Sort(has_less_than<UseClass>::value); }
private:
bool Sort(std::true_type)
{
sort(m_classlist.begin(), m_classlist.end());
return true;
}
bool Sort(std::false_type) { return false; }
};
Update: As per your comment here is a C++03 implementation:
template <typename T>
class has_less_than {
struct Fallback { bool operator<(T const&); };
struct Derived : T, Fallback {};
template <typename U, U> struct S;
template <typename C> static char (&f(S<bool (Fallback::*)(T const&), &C::operator<>*))[1];
template <typename C> static char (&f(...))[2];
public:
const static bool value = sizeof(f<Derived>(0)) == 2;
};
namespace detail
{
template <bool B, typename R = void>
struct enable_if { typedef R type; };
template <typename R>
struct enable_if<false, R> { };
}
template <class UseClass> class Container {
public:
bool Sort() { return Sort<UseClass>(); }
private:
template <typename T>
bool Sort(typename detail::enable_if<has_less_than<T>::value, int>::type = 0) {
sort(m_classlist.begin(),m_classlist.end());
return true;
}
template <typename T>
bool Sort(typename detail::enable_if<!has_less_than<T>::value, int>::type = 0) {
return false;
}
private:
vector<UseClass> m_classlist;
};

enable_if type is not of a certain template class

TLDR: See the last paragraph.
I have an operator& defined for several template classes like so:
template <typename T>
struct Class {
Class(T const &t) { }
};
template <typename T_Lhs, typename T_Rhs>
struct ClassAnd {
ClassAnd(T_Lhs const &lhs, T_Rhs const &rhs) { }
};
template <typename T, typename T_Rhs>
ClassAnd<Class<T>, T_Rhs> operator&(Class<T> const &lhs, T_Rhs const &rhs) {
return ClassAnd<Class<T>, T_Rhs>(lhs, rhs);
}
template <typename T0, typename T1, typename T_Rhs>
ClassAnd<ClassAnd<T0, T1>, T_Rhs> operator&(ClassAnd<T0, T1> const &lhs, T_Rhs const &rhs) {
return ClassAnd<ClassAnd<T0, T1>, T_Rhs>(lhs, rhs);
}
int main() {
Class<int> a(42);
Class<double> b(3.14);
auto c = a & b;
}
This works just fine.
The problem occurs when I want to add a not operation, which is allowed on only one side or the other of an and operation, and must return an instance of ClassAndNot rather than ClassAnd:
template <typename T>
struct ClassNot {
ClassNot(T const &t) : value(t) { }
T value;
};
template <typename T_Lhs, typename T_Rhs>
struct ClassAndNot {
ClassAndNot(T_Lhs const &lhs, T_Rhs const &rhs) { }
};
template <typename T_Lhs, typename T_Rhs>
ClassAndNot<T_Lhs, T_Rhs> operator&(T_Lhs const &lhs, ClassNot<T_Rhs> const &rhs) {
return ClassAndNot<T_Lhs, T_Rhs>(lhs, rhs.value);
}
template <typename T_Rhs>
ClassNot<T> operator!(T_Rhs const &rhs) {
return ClassNot<T_Rhs>(rhs);
}
...
auto c = a & !b;
This results in an ambiguity between the operator& taking an arbitrary right hand side to return a ClassAnd, and the operator& taking a ClassNot right hand side to return a ClassAndNot.
Question:
How could std::enable_if be used here to disable the first operator& if its right hand side is of any of the types ClassNot? Is there something like std::is_same that returns true if one side is a template instance of the other?
p.s. You can find a full working example on ideone.
You should be able to construct your own trait for this:
template <class T>
struct IsClassNot : std::false_type
{};
template <class T>
struct IsClassNot<ClassNot<T>> : std::true_type
{};
template <typename T, typename T_Rhs>
typename std::enable_if<!IsClassNot<T_Rhs>::value,
ClassAnd<Class<T>, T_Rhs>>::type operator&(Class<T> const &lhs, T_Rhs const &rhs) {
return ClassAnd<Class<T>, T_Rhs>(lhs, rhs);
}
Live example
Of course, you can go crazy with generalisations and create an all-purpose trait:
template <class T, template <class...> class TT>
struct is_instantiation_of : std::false_type
{};
template <template <class... > class TT, class... A>
struct is_instantiation_of<TT<A...>, TT> : std::true_type
{};
template <class T>
using IsClassNot = is_instantiation_of<T, ClassNot>;
Live example

class template that takes function template arguments that operate on an instance of the class being defining

I would like to define a class template that takes function template arguments that operate on an instance of the class being defining.
Is this or something analogous possible?
I know that I could define conversion constructors, but for reasons not clear from this simplified example I want to be able to alter the functionality of the class with out changing its definition or creating derived types.
I know that I could include function pointer members and use setters to fix their functionality, but I would prefer to fix the functionality of the class using a declarative typedef rather than programmatically.
template
< typename T
, MyClass<X> (to_X)(MyClass<T>)
, MyClass<T> (from_X)(MyClass<X>)
>
class MyClass {
T value;
MyClass(T v) : value(v) {}
// is it possible to use to_X and from_X template args
// to declare member functions ...
}
MyClass<int> to_int(MyClass<std::string> value ) {
// return result of conversion
}
MyClass<std::string> to_string(MyClass<int> value ) {
// return result of conversion
}
MyClass<std::string, to_string, to_int> foo1 =
MyClass<std::string, to_string, to_int>("5");
MyClass<int, to_int, to_string> * foo2 = foo1.to_int();
I suggest you to use a policy-classes approach: Your class template is parametrized with the two conversion policies
template<typename T,
typename FROM,
typename TO
>
class MyClass
{
FROM from_t_conversion;
TO to_t_conversion;
MyClass() = default;
template<typename U>
operator U() const
{
return from_t_conversion( *this );
}
template<typename U>
MyClass( const U& u ) : MyClass()
{
std::swap( *this , to_t_conversion( u ) );
}
};
The point of this design is the type (form) of a conversion policy: A conversion policy could be any callable entity with the expected signature: A function, a functor, a lambda, etc.
EDIT: Here is an example of converters:
struct float_to_int
{
MyClass<itn> operator()( const MyClass<float>& )
{
return MyClass<int>{};
}
};
//A more generic conversion function:
template<typename T>
struct generic_to_converter
{
template<typename U , typename X = T>
MyClass<X> operator()( const MyCLass<U>& )
{
return /* something /*
}
};
Maybe don't overthink this and keep it simple:
template <typename T, typename Converter>
class MyClass
{
T value;
Converter converter;
public:
explicit MyClass(T const & v, Converter const & c = Converter())
: value(v), converter(c)
{ }
template <typename U, typename C = Converter>
operator MyClass<U, C>() const
{
return converter.template convert<U, C>(*this);
}
};
Your converter needs to look like this:
struct ExampleConverter
{
template <typename U, typename C1, typename T, typename C2>
MyClass<U, C1> convert(MyClass<T, C2> const &) const;
};
With a little bit more effort, you could take advantage of base class layout optimizations (in the same way that standard library implementations usually take care of allocators and comparators).
You could also have some rebind mechanic to allow the converter to be itself a template.
template <typename T, typename Converter = StandardConverter<T>>
class MyClass
{
T value;
Converter converter;
public:
explicit MyClass(T const & v, Converter const & c = Converter())
: value(v), converter(c)
{ }
template <typename U,
typename C = typename Converter::template rebind<U>::type>
operator MyClass<U, C>() const
{
return converter.template convert<U, C>(*this);
}
};
template <typename T>
struct StandardConverter
{
template <typename U, typename C>
MyClass<U, C> convert(MyClass<T, StandardConverter<T>> const &) const;
template <typename U> struct rebind { using type = StandardConverter<U>; };
};

specialize template function for template class

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)
{
/* ... */
}