How to limit a templated function if a specialization exist? - c++

I'm writing a library for which each value type can be converted to string using a to_string() free function.
I'd like to enable std::ostream& operator<<(std::ostream&, _) for all types T for which to_string(T) is valid. Here is my try:
namespace mylibrary {
// All my types are declared in the `mylibrary` namespace so that ADL is happy.
template <typename T>
inline std::string to_string(const T& value) {
// Return a string for value. Doesn't really matter how.
}
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const T& value) {
return os << to_string(value);
}
}
This actually works... but a bit too well: when resolving os << to_string(value) my templated operator<<() is picked up as candidate even for std::string which sadly makes the call ambiguous an ends up in a compiler error.
I tried using std::enable_if<> to conditionnaly disable my operator<< but sadly I couldn't get something that compiles.
How can I restrict my operator<<() for types for which to_string(T) is a valid expression ?
Alternatively, is there way to restrict my operator<<() for types which are defined in my namespace ?

You can use expression-SFINAE to restrict the template overload set. For example like this:
#include <string>
#include <type_traits>
template <typename> using void_t = void;
template <typename T, typename = void_t<decltype(to_string(std::declval<T>()))>>
std::ostream& operator<<(std::ostream& os, const T& value) {
return os << to_string(value);
}
(You should probably wrap this up somehow so as not to have a visible second template parameter in your public template; users will discover and abuse it.)

namespace details{
template<template<class...>class,class,class...>
struct can_apply:std::false_type{};
template<template<class...>class Z,class...Ts>
struct can_apply<Z,std::void_t<Z<Ts...>>,Ts...>:
std::true_type
{};
}
template<template<class...>class Z,class...Ts>
using can_apply=details::can_apply<Z,void,Ts...>;
is a small metaprogramming library that gives you the can_apply<template, types...> trait. It uses C++1z std::void_t which is easy to write if your compiler lacks it.
template<class X>
using to_string_t=decltype(to_string(std::declval<X>()));
is a SFINAE enabled "type of calling to_string" (either string or error, we hope). We stitch together:
template<class X>
using can_to_string=can_apply<to_string_t,X>;
and we have a trait can_to_string which is true iff you can to_string. Both of the above two using templates shoud be in the same namespace as your to_string for built-in types for adl reasons.
Now we can write our <<:
template <class T,class=std::enable_if_t<can_to_string<const T&>{}>>
inline std::ostream& operator<<(std::ostream& os, const T& value) {
return os << to_string(value);
}
The modest metaprogramming library overhead makes the final code much cleaner than alternatives.
enable_if_t is C++14 but also easy to write in C++11. You may have to replace {} with ::value in C++11 within the enable_if as well.
The result_t using alias is one line, the can_ alias is another, and then we have a friendly can_ alias for almost any bit of C++ code, which allows for clean enable_if SFINAE.
All of this can be done on one line, but I find the resulting << interface to be less than clear in what the requirements are.

Related

concept using helper class

In order to be able to write stuff like cout << vec for iterable types like vector<int> vec;, I wanted to define operator<<(osteam&, const T&) for iterable T only. My first shot was
template<class T> using extract_iterator_t = typename T::iterator;
template<class T> concept iterable = requires { typename extract_iterator_t<T>; };
template<iterable T>
ostream& operator<<(ostream& os, const T& seq) {
for(const auto& i: seq) os << i << ',';
return os;
}
but that misses iterable things like int*, so I replaced the first line by
template<class T> struct extract_iterator { using type = T::iterator; };
template<class T> struct extract_iterator<T*> { using type = T*; };
template<class T> struct extract_iterator<T[]> { using type = T*; };
template<class T> using extract_iterator_t = typename extract_iterator<T>::type;
However, now g++-11.1 refuses to compile this, saying
error: 'char' is not a class, struct, or union type
because it tries to use my custom operator<< for the <<',' part, rightfully complaining about a substitution failure. However, I always thought Substitution Failure Is Not An Error, so why would g++ insist on using my custom operator<< for <<','?
Here's the godbolt: https://godbolt.org/z/jejexE18h
Edit: everyone pointing out ranges is correct that they are the right tool to use for this, but this example was just to illustrate a problem I have with a construct similar but not equal to ranges - I thought I'd present a minimum breaking example instead of telling a long introductory story which boils down to the same problem.
The issue is that in your primary definition:
template <class T> struct extract_iterator { using type = T::iterator; };
the failure that happens when we try to do T::iterator is outside of the immediate context of the substitution, so it is not SFINAE-friendly.
You could fix this by adding the right constraint:
template<class T> struct extract_iterator;
template<class T> requires requires { typename T::iterator; }
struct extract_iterator<T> { using type = T::iterator; };
But this whole approach is wrong anyway. T* isn't iterable, it's an iterator. And C++20 already comes with the tool you need for this job: Ranges:
template <std::ranges::range R>
std::ostream& operator<<(std::ostream& os, R&& seq);
Note that this is problematic anyway for other reasons, and you should instead just use fmt which comes with direct support for formatting ranges in a proper way.

Prevent instantiation of template class for types not supported by stringstream extraction operator (>>)

I'm trying to learn a bit about templates and metafunctions, namely std::enable_if. I'm making a menu system for our school assignments (extracurricular, mind you), and need a way of getting input from the user. I'd like to define a template class for various types of input - something used along the lines of:
std::string userInput = Input<std::string>("What's your name?").Show();
float userHeight = Input<float>("How tall are you?").Show();
I'd like to (and I'm sure there are reasons not to, but nevertheless) do this generalized sort of conversion using a std::stringstream: get input from user, feed into SS, extract into variable of type T.
It's easy enough to see if the conversion failed during runtime, but I'd like to use std::enable_if to prevent people from using my Input<> class for cases where conversion is impossible, say:
std::vector<Boats> = Input<std::vector<>>("Example").Show();
Obviously a std::stringstream cannot convert a string to a vector, so it will always fail.
My question is this:
Can I format an std::enable_if clause to ONLY allow instantiation of my template class for the types listed above? Alternatively, is there a better way to go about it? Have I got things completely the wrong way around?
What I've done so far
I believe I have found a list of allowed types that std::stringstream can "convert" a string into:
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
I've been using std::enable_if like this up until this point:
template <typename T, typename = typename
std::enable_if<std::is_arithmetic<T>::value, T>::type>
However, now I'd like to extend it to allow not only arithmetic values, but all values supported by the sstream >> operator.
If you prefer to use a SFINAE with a class template parameter, then you want
template <
typename T,
typename = decltype(std::declval<std::istringstream &>() >> std::declval<T &>(), void())
>
class Input /*...*/
I think that you are trying to use std::enable_if for something which doesn't require it. If your template function already relies on operator<< applied on a generic type T, then compilation will fail in any case if the operator is not specialized for that type.
Nothing prevents you from using std::enable_if to solve your specific problem, though that may be not the best way to do it.
If C++20 concepts were already largely adopted I'd say that that would be your way to go.
You could go the way as suggested here on SO and implement a class is_streamable which can check for that like this:
#include <type_traits>
#include <utility>
#include <iostream>
#include <sstream>
template<typename S, typename T>
class is_streamable
{
template<typename SS, typename TT>
static auto test(int)
-> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
template<typename, typename>
static auto test(...)->std::false_type;
public:
static const bool value = decltype(test<S, T>(0))::value;
};
class C
{
public:
friend std::stringstream& operator<<(std::stringstream &out, const C& c);
};
std::stringstream& operator<<(std::stringstream& out, const C& c)
{
return out;
}
int main() {
std::cout << is_streamable<std::stringstream, C>::value << std::endl;
return 0;
}
This would return one if the operator is implemented and zero if not.
With that you can alter your snippet to
template <typename T, typename = typename
std::enable_if<is_streamable<std::stringstream, C>::value, T>::type>
There are several thing you want:
a trait, is_streamable
a way to forbid class instantiation.
For the traits, you might use std::experimental_is_detected or run your own:
template <typename T>
auto is_streamable_impl(int)
-> decltype (T{},
void(), // Handle evil operator ,
std::declval<std::istringstream &>() >> std::declval<T&>(),
void(), // Handle evil operator ,
std::true_type{});
template <typename T>
std::false_type is_streamable_impl(...); // fallback, ... has less priority than int
template <typename T>
using is_streamable = decltype(is_streamable_impl<T>(0));
Then to forbid intantiation, several choices:
static_assert:
template <typename T>
class Input
{
static_assert(is_streamable<T>::value);
// ...
};
or SFINAE friendly class:
template <typename T, typename = std::enable_if_t<is_streamable<T>>>
class Input
{
// ...
};
so you allow to know if Input<T1> is valid.
Notice that without all that stuff, your program won't compile anyway when instantiating the problematic method (hard error, so no SFINAE friendly).
Being SFINAE friendly is not necessary most of the time.

Enable a template depending on whether a certain function exists

I would like to design a template that automatically provides an operator<<(std::ostream&, const T&) for all classes T for which T::print_to(std::ostream&) exists and can be called, so that I can define the printing function as a member function (and, in particular, take advantage of virtual calls).
Through trial and error, I managed to arrive at this:
template<typename T, typename = decltype(std::declval<T>().print_to(std::declval<std::ostream&>()))>
std::ostream &operator<<(std::ostream &s, const T &t) {
t.print_to(s);
return s;
}
It seems to be working, but since I am still new to SFINAE and this kind of tricks, would like to know if there is any pitfall or enhancement that can be made. I put a small test bench at https://ideone.com/uLJxac.
If possible, I would like to have a C++14 solution, because I am working with a C++14 code base. However, if using C++17 allows for a better solution, than I am also interested to that one.
It seems to me that your applying SFINAE correctly in your operator<<(); I don't see pitfalls in your solution.
I propose another version (C++11 compatible, so also C++14) just because require less typewriting
template <typename T>
auto operator<< (std::ostream & s, T const & t)
-> decltype( t.print_to(s), s )
{
t.print_to(s);
return s;
}
Edit:
There is no pitfall with your code, sorry about that. But this answer enables you to write code more like C++20 concept:
template <class T>
auto& operator << (std::ostream &out, const printable_t<T> &t)
{
t.print_to(out);
return out;
}
In fact, I wrote a C++17 concept_check library based on detector and can be used in this way.
For more info on concept support in C++20, have a look at these 2:Constraints and concepts (since c++20) and Constraints and concepts (TS)
Original answer:
std::experiment::is_detector can do the magic for you. Though it is not in standard library, it is not difficult to implement and that link gives the suggested implementation.
Here I will give you how to detect that function along with my implementaion of is_detected_v.
#include <type_traits>
#include <utility>
#include <ostream>
// For support for C++17 is not complete in many compiler, I also define void_t
template <class...> using void_t = void;
namespace impl {
template <class Default, class AlwaysVoid, template <class...> class Op, class ...Args>
struct detector: private std::false_type
{
using std::false_type::value;
using type = Default;
};  
template <class Default, template <class...> class Op, class ...Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>: private std::true_type
{
using std::true_type::value;
using type = Op<Args...>;
};
} // namespace impl
struct nonsuch {};
#define CONCEPT_T constexpr const static inline bool
template <template<class...> class Op, class ...Args>
CONCEPT_T is_detected_v = impl::detector<nonsuch, void, Op, Args...>::value;
// Detect whether print_to exists.
template <class T>
using print_to_ret_t = decltype( std::declval<T>().print_to( std::declval<std::ostream&>() ) );
template <class T>
CONCEPT_T has_func_print_to_v = is_detected_v<print_to_ret_t, T>;
template <class T, std::enable_if_t< has_func_print_to_v<T> >>
using printable_t = T;
#undef CONCEPT_T
You can try to add C++14 support to this code. It won't be too difficult. The CONCEPT_Tmust be changed to constexpr const static bool to adjust to C++14.

Why is it not possible to override operator<< for template classes involving third-party code?

I asked about the following in https://stackoverflow.com/a/51951315/1908650 :
I want to overload template<class T> ostream& operator<<(ostream& os, const optional<unique_ptr<T>>&).
In the comments, #Yakk - Adam Nevraumont notes:
The answer to that question is "you cannot". There is no good legal way to do that for a generic type T; I could explain why, but it would take a new question/answer to do so
I'm creating a new Q. to take up the kind offer...
The proper place to overload operators in in the namespace associated with the type.
For std::optional<std::unique_ptr<T>> there is one associated namespace std that is always there (from ostream and optional and unique_ptr), plus whatever namespace is associated with T. As you want to overload for all types, the namespace(s) associated with T are not useful to you.
It is not legal to introduce a new function or overload into std; in certain limited circumstances you can introduce specializations, but none of them apply here. Adding a new overload of << to std makes your program ill formed, no diagnostic required.
You could (A) use decorated unique_ptr or optionals from your own namespace, or (B) use a decorated ostream, or (C) write a formatter wrapper:
namespace fmt {
template<class T>
struct wrapper_t {
T&& t;
};
template<class T>
struct is_wrapped:std::false_type{};
template<class T>
struct is_wrapped<wrapper_t<T>>:std::true_type{};
template<class OS, class T,
std::enable_if_t<!is_wrapped<OS&>{}, bool> =true
>
auto operator<<( OS& os, wrapper_t<T>&& w )
-> decltype( os << std::forward<T>(w.t) )
{ return os << std::forward<T>(w.t); }
template<class OS, class T>
auto operator<<( wrapper_t<OS&> os, T&& t )
-> decltype( os.t << std::forward<T>(t) )
{ return os.t << std::forward<T>(t); }
template<class T>
wrapper_t<T> wrap(T&& t){ return {std::forward<T>(t)}; }
}
then std::cout << fmt::wrap( foo ) can find overloads of << within fmt, and if none are found invokes << on the contained data.
This also supports fmt::wrap(std::cout) instead of wrapping the arguments. There are probably typos.
In addition to what has been said, there's another issue involving ODR problems. If you overload a function for types you don't control, it is conceivable that someone else also overloads it differently. Then you compile your code with your overload, they compile their code with their overload, and when you work for the same company you end up with multiple versions of the same-signature function in different translation units. Again, undefined behavior, no diagnostic required.
Sanitizers may find this, and perhaps it sounds contrived, but such things happen from time to time.

How do I write an ADL-enabled trailing return type, or noexcept specification?

Imagine I'm writing some container template or something. And the time comes to specialize std::swap for it. As a good citizen, I'll enable ADL by doing something like this:
template <typename T>
void swap(my_template<T>& x, my_template<T>& y) {
using std::swap;
swap(x.something_that_is_a_T, y.something_that_is_a_T);
}
This is very neat and all. Until I want to add an exception specification. My swap is noexcept as long as the swap for T is noexcept. So, I'd be writing something like:
template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
noexcept(noexcept(swap(std::declval<T>(), std::declval<T>())))
Problem is, the swap in there needs to be the ADL-discovered swap or std::swap. How do I handle this?
I think I would move it into a separate namespace
namespace tricks {
using std::swap;
template <typename T, typename U>
void swap(T &t, U &u) noexcept(noexcept(swap(t, u)));
}
template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
noexcept(noexcept(tricks::swap(std::declval<T>(), std::declval<T>())))
{
using std::swap;
swap(x.something_that_is_a_T, y.something_that_is_a_T);
}
Alternatively you can move the whole code up into tricks and delegate to there.
There is a similar problem for return types:
// Want to be compatible with both boost::tuple and std::tuple
template<typename Tuple>
auto first(Tuple&& tuple)
-> /* ??? */
{
// Introduce name into scope
using std::get;
// but ADL can still pick boost::get for boost::tuple
return get<0>(std::forward<Tuple>(tuple));
}
Using decltype( get<0>(std::forward<Tuple>(tuple)) ) isn't correct as get isn't in scope.
Possible workarounds are:
Introducing a dummy template (get in my example, swap in your case) in the enclosing scope; this includes putting the using std::swap declaration in the enclosing namespace, with the drawback of polluting the namespace.
Use of a type trait: typename std::tuple_element<0, typename std::remove_reference<Tuple>::type>::type (actually this one is problematic but for reasons that don't belong here) in my example, and a potential is_nothrow_swappable<T>::value in your case. Specializations then allow the template to be extended for other types if need be.
Rather than declaring but not defining a function template, which seems likely to cause confusion, I would write my own type trait (which is what should probably be in the standard library, anyway). Following the lead of the standard library, I would define something like the following:
#include <type_traits>
#include <utility>
namespace adl {
using std::swap;
template<typename T, typename U>
struct is_nothrow_swappable : std::integral_constant<
bool,
noexcept(swap(std::declval<T &>(), std::declval<U &>()))
> {
};
} // namespace adl
We have to define our own namespace to import std::swap into (to avoid giving it to everyone), but of course, if it were in the standard library that wouldn't be necessary because they can already make unqualified calls to swap.
C++17 has solved this particular use case with std::is_nothrow_swappable: http://en.cppreference.com/w/cpp/types/is_swappable