Consider these two functions:
template <class Type,
class = typename std::enable_if</*HAS OPERATOR <<*/>::type>
void f(std::ostream& stream, const Type& value);
template <class Type,
class... DummyTypes,
class = typename std::enable_if<sizeof...(DummyTypes) == 0>::type>
void f(std::ostream& stream, const Type& value, DummyTypes...);
As the non-variadic overload has the priority over the variadic overload, I want to check whether the type has the operator<< with an std::ostream using std::enable_if in the first version.
So what should I write instead of /*HAS OPERATOR <<*/ ?
The following should work
template <class Type,
class = decltype(std::declval<std::ostream&>() << std::declval<Type>())>
void f(std::ostream& stream, const Type& value)
{
stream << value;
}
(note you don't need to use std::enable_if in this case)
Using trailing return type (1), you can actually have a foretaste of concepts:
template <typename Type>
auto f(std::ostream& out, Type const& t) -> decltype(out << t, void()) {
// ...
}
Because of SFINAE, this overload can only be selected if the type of out << t can be resolved, and this implies that an overload of << exists that accepts both parameters.
The one pitfall is that this does not work if you need the contrary, that is enabling a function if this overload does not exists. In this case an enable_if strategy (and the symmetric disable_if) is necessary, as far as I know.
(1) thanks to Simple for helping out with the syntax
It is easiest to check when you have the arguments around, i.e., I would rather try to use something like this:
template <typename Type>
auto f(std::ostream& out, Type const& value)
-> typename std::enable_if<sizeof(out << value) != 0>::type {
...
}
A similar effect could be obtained using std::declval() but off-hand I'm not sure about creating references.
Related
Recently I posted this question : Ambigous operator overload on clang which got closed for being essentially the same as Is clang wrongfully reporting ambiguity when mixing member and non-member binary operators?
After reading answers to that other question, I think I am still confused about what more specialized means. So based on what I read there, the member operator from my code should resolve to this :
template <class U>
TVector3<T>& TVector3<float>::operator*=(const U ) { return *this; }
during name lookup and for the purpose of overload resolution I would get these two candidates:
template <class U>
TVector3<T>& operator*=(TVector3<float>&, const U ) { return *this; }
template <typename T>
TVector3<T>& operator*=(TVector3<T>& v, const TMatrix3<T>& ) { return v; }
Why are they both equally well specialized ?
Is it because in the first overload the first argument is more specialized, while in the second overload the second argument is more specialized ? So basically a tie between them ?
On the other hand, if I turned the member operator*= of the Vector class into a free function, the overload resolution set would be:
template <class T, class U>
TVector3<T>& operator*=(TVector3<T>& v, const U ) { return v; }
template <typename T>
TVector3<T>& operator*=(TVector3<T>& v, const TMatrix3<T>& ) { return v; }
in which case the first argument of both overloads is equally specialized, but the second argument of the second overload is more specialized and thus no ambiguity in this case.
Is my understanding correct ?
I am trying to learn how to use SFINAE.
For practice purposes, I was trying to make an std::ostream wrapper in order to make a custom formatter.
Here is my SFINAE and custom output class.
// Tester
template <class O>
struct is_ostreamable {
template <class T>
static auto check(T t) -> decltype(std::declval<std::ostream &>() << t, std::true_type());
template <class>
static auto check(...) -> std::false_type;
public:
static constexpr bool value{std::is_same_v<decltype(check<O>(0)), std::true_type>};
};
// Custom class
struct CustomOutput {
// Constructor etc...
CustomOutput(std::ostream &os = std::cout) : os{os} {}
std::ostream &os;
// Problematic template function
template <class O, class = std::enable_if_t<is_ostreamable<O>::value>>
CustomOutput &operator<<(O o) {
os << o;
return *this;
}
};
It words perfectly to not enable the template for struct or class that cannot be printed via operator<<.
However, with this SFINAE, ostream manipulators are not working... And I can't figure out why.
The error, and my expectations:
int main(void){
CustomOutput{} << "hi"; // Fine
std::vector<int> vec;
// CustomOutput{} << vec; // Error. Expected
CustomOutput{} << std::endl; // Error. WHY?
}
Maybe I missed something? Any help would be greatly appreciated.
First, fix your ostreamable class. Currently, your class requires T to be copy-constructible from 0. This is not the case for many classes. It should use std::declval to create the value instead:
template <class O>
struct is_ostreamable {
template <class T>
static auto check(int) -> decltype(std::declval<std::ostream &>() << std::declval<T>(), std::true_type());
template <class>
static auto check(...) -> std::false_type;
public:
static constexpr bool value{std::is_same_v<decltype(check<O>(0)), std::true_type>};
};
Two changes are made here:
The operand to decltype uses std::declval<T>() to create the object of type T. std::declval<T> is an (intentionally undefined) function template that generates an object of type T when used in an unevaluated operand (such as that to decltype, or sizeof, noexcept operator, etc.) without dependence on a specific construction signature (copy-construction from 0 in your case).
The parameter to check is replaced with int. The initializer of the value variable calls check with the argument 0, so this int parameter ensures that (int) ranks higher than (...) in overload resolution, so that the true_type overload gets chosen when possible.
You need to provide a special overload for function-style manipulators (std::endl, std::flush, etc.):
using manip = std::ostream& (*)(std::ostream&);
CustomOutput& operator<<(manip m) {
os << m;
return *this;
}
There is, unfortunately, no way to make the generic template version support this feature. This is because std::endl is a function template:
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>& endl(td::basic_ostream<CharT, Traits>& os);
For a function template to be used, the appropriate template arguments have to be determined. It is not possible to deduce the type-template parameter T as a generic template.
Anyway, this is probably the only special overload you are going to need.
I know there is already an accepted answer but I would like to mention a bit prettier C++20 way of doing the same thing by using concepts:
#include <iostream>
#include <concepts>
using OManipulator= std::ostream&(&)(std::ostream &);
template <typename T>
concept OStreamable = requires(T t) {
std::declval<std::ostream&>() << t;
};
struct CustomOutput {
std::ostream &os;
CustomOutput(std::ostream &os = std::cout)
: os{os}
{}
template <typename T> requires OStreamable<T>
CustomOutput& operator<<(T out) {
os << out;
return *this;
}
CustomOutput& operator<<(OManipulator out) {
os << out;
return *this;
}
};
int main(void){
CustomOutput{} << "hello";
CustomOutput{} << std::endl;
CustomOutput{} << "world";
}
Basically, in C++20, problem with manipulators needs to be solved in the same way as pre-C++20, by providing a special overload for them.
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.
I need a function that will take two iterators and a custom comparator to compare values of this iterators. I don't want use additional template argument for this. I've implemented it in this way:
template<typename T>
void foo(T begin, T end,
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
{
// I want to use 'compare' as: "compare(*begin, *begin);"
}
This code has been compiled normally by clang, but on GCC 5.4.0 I've got some errors:
binary_heap.cpp:10:79: error: local variable 'begin' may not appear in this context
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
^
binary_heap.cpp:10:85: error: template argument 1 is invalid
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
How to correct this code so that it can be successfully compiled on both clang and GCC? Or maybe are there a more suitable solution for defining such function?
You cannot use a parameter in a default argument, even in an unevaluated context (although the Standard should probably be amended to loosen that restriction). Instead of decltype(*begin), use
decltype(*std::declval<T&>())
Edit: Actually, that probably doesn't do what you want, since if applying the * operator yields an lvalue, then the decltype specifier will resolve to an lvalue reference, but you would want the unreferenced type to be the argument to std::less. Better to use:
typename std::iterator_traits<T>::value_type
Edit 2: I agree with krzaq, it's better to just add another template parameter.
You're pessimizing performance of your algorithm by a lot just by forcing the use of function (more details here). Just take template deduced Compare and you're golden:
template<typename T, typename Compare = std::less<typename iterator_traits<T>::value_type>>
void foo(T begin, T end, Compare compare = {})
{
// I want to use 'compare' as: "compare(*begin, *begin);"
}
Interestingly, standard algorithms force/suggest use of lightweight functors by taking them by value instead of a forwarding reference.
To answer the actual question: you can use std::less<>, which defaults to std::less<void> and has templated operator() doing the actual comparisons:
template<typename T>
void foo(T begin, T end,
function<bool(decltype(*begin), decltype(*begin))> compare = less<>())
{
// I want to use 'compare' as: "compare(*begin, *begin);"
}
Add another template parameter Compare. This makes inlining easier by the compiler. While I'm at it support Sentinels.
template<class It, class Sentinel, class Compare=std::less<void>>
void foo(It begin, Sentinel end, Compare cmp={}) {
}
However, assuming C++14, barring the above, I'd do this:
template<class T>
using comparator_sig = bool(T const&,T const&);
template<class T>
using comparator = std::function<comparator_sig<T>>;
template<class It>
using compare_inside_it = comparator<
typename std::iterator_traits<It>::value_type
>;
template<typename T>
void foo(T begin, T end, compare_inside_it<T> compare = less<>) {
}
in C++11 I would write my own less<void>:
struct compare_less {
template<class T>
bool operator()( T const& lhs, T const& rhs ) const {
return std::less<T>{}(lhs, rhs);
}
};
and do:
template<typename T>
void foo(T begin, T end, compare_inside_it<T> compare = compare_less{}) {
}
or even just do:
template<typename T>
void foo(T begin, T end, compare_inside_it<T> compare = {}) {
if (!compare) compare=compare_less{};
}
How would you go about writing a library that, when included, it overloads the << operator for any* existing STL container?
Except adaptors like stack and queue, since you cannot iterate through them.
The one self-imposed requirement is that it mustn't include any of the containers' header files. That would bloat the final executable unnecessarily. It makes more sense to include this header after the containers' that I would like to work with. This restriction implies the use of templates or macros.
I'm looking for advice and pointers, so, please, don't just post fully working code that can do this! Implementing this myself is part of the learning process. Small snippets of code that demonstrate how certain things work are welcome.
What I did up to this point:
I have overloaded the << operator for every container with a different template signature. The problem that I have run into with this approach is, that there are containers that have the same number of template parameters, but some contain std::pair-s, others single values. More precisely, this is the case of std::map & std::multimap vs std::unordered_set & std::unordered_multiset.
This collision forces me to either implement a non-template version of one of the pairs, or to come up with a way to differentiate between std::pair-s and single values. I don't really know how to go about doing the second one, though. The reason because I'm not "how to do that" directly is that I'm starting to believe that this could be avoided entirely with a better overall design.
Thank you in advance!
What worked for me:
Overload operator<< for std::pair
Overload operator<< for every STL container with different template arguments
Note:
template <typename T1> and template <typename T1, typename T2> are different
template <typename T1, typename T2> and template <typename T1, size_t T2> are
different
template <typename T1, typename T2> and template <typename C1, typename C2>
are NOT different
Put them in a namespace to make sure that your operators won't collide with any other operators that you might need in the future.
Use "templates in templates", so for example a function would look like:
template <typename Type, template <typename TYPE> class TClass>
void func(TClass<Type>& tc) {
if (tc.somethingTrue())
tc.doStuff();
}
You could overload operator<< as a template that takes a template template argument (i.e., any container).
Then you could provide two overloads of a template function (e.g., print) that the one overload would specialize on std::pair.
template<typename T>
std::ostream& print(std::ostream &out, T const &val) {
return (out << val << " ");
}
template<typename T1, typename T2>
std::ostream& print(std::ostream &out, std::pair<T1, T2> const &val) {
return (out << "{" << val.first << " " << val.second << "} ");
}
template<template<typename, typename...> class TT, typename... Args>
std::ostream& operator<<(std::ostream &out, TT<Args...> const &cont) {
for(auto&& elem : cont) print(out, elem);
return out;
}
LIVE DEMO
A very simple attempt at this problem is something like:
template<typename T>
void print_container(std::ostream& os, const T& container, const std::string& delimiter)
{
std::copy(std::begin(container),
std::end(container),
std::ostream_iterator<typename T::value_type>(os, delimiter.c_str()));
}