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.
Related
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 want to create a template class which has an iterator of a STL container as a member. That is how far I got:
#include <iostream>
#include <vector>
using namespace std;
template<typename Element, template <class> class StdLibContainer>
struct ClassHoldingAnIteratorToAStandardContainer
{
ClassHoldingAnIteratorToAStandardContainer(){}
typename StdLibContainer<Element*>::iterator std_lib_iterator;
};
int main()
{
vector<int> vec{1,2,3};
ClassHoldingAnIteratorToAStandardContainer<int,vector<int>> holding_iterator_to_vec;
//DOES NOT WORK, compiler says: expected a class template, got ‘std::vector<int>’
return 0;
}
Could you explain the syntax template <typename> class StdLibContainer?
I found it somewhere on stackoverflow. BUt I don't understand it.
How can I create an instance of ClassHoldingAnIteratorToAStandardContainer ? All my attempts failed so far. The compiler always gives the error message: `expected a class template, got ‘std::vector’
In the above example i want to assign holding_iterator_to_vec vec.begin().
template <typename> class is the same as template <class> class. Originally, when templates were introduced, they allowed two equivalent forms:
template<class T> struct Foo {};
// or
template<typename T> struct Foo {};
Do not ask me why! However, the same was not true for template template parameters:
template <template <class> typename T> struct Foo {};
was the only allowed syntax. Apparently, people were unhappy about it, so the syntax was relaxed.
As for your second question, std::vector takes at least two template arguments, data type and allocator. This is why a single argument template doesn't cut it before C++17. After C++17, it would work.
To make it universal, use
template<template <class...> class Container> struct Foo{};
Unless you really need to know the type of the container, I would strongly recommend to keep your ClassHoldingAnIteratorToAStandardContainer independent of the concrete container type. If you just need the iterator, this is simpler and sufficient:
template<typename iterator>
struct iterator_wrapper {
iterator iter;
};
Thats the minimum you need to have an iterator as member :).
I dont really know what you want to use the iterator for, so just for the sake of an example lets add methods that actually use the iterator....
#include <iterator>
#include <vector>
#include <iostream>
template<typename iterator>
struct iterator_wrapper {
using value_type = typename std::iterator_traits<iterator>::value_type;
iterator iter;
bool operator!=(const iterator& other) { return iter != other;}
iterator_wrapper& operator++(){
++iter;
return *this;
}
const value_type& operator*() { return *iter; }
};
template <typename iterator>
iterator_wrapper<iterator> wrap_iterator(iterator it) {
return {it};
}
int main() {
std::vector<int> vec{1,2,3};
auto it = wrap_iterator(vec.begin());
for (;it != vec.end();++it) std::cout << *it;
}
Also there is a problem in your code.
typename StdLibContainer<Element*>::iterator
is for containers of pointers while in main you have ints. If you want to infer the iterator type from the container type then you can do it for example like this:
template <typename container,
typename iterator = typename container::iterator>
iterator_wrapper<iterator> wrap_begin(container& c) {
return {c.begin()};
}
which makes creating an iterator_wrapper as simple as
auto x = wrap_begin(vec);
Note that this answer applies to C++11, in newer standards there are deduction guides that make such make_x methods more or less superfluous afaik.
Imagine some function (RetrieveResult), returning an object by pointer/reference/value - I don't know and don't want to know, because things may change. I just want to store the result, using auto and also protect that object from accidental changing in the current scope or, for example, if the object is propagated upwards.
It is quite intuitive just to write:
const auto result = RetrieveResult();
and everything works fine, if RetrieveResult returns an object by value or by reference. But if the function returns a pointer, constancy is applied to that pointer, not to the object the poiter points to. What way I still can change the object. Writing
const auto const result = ....
results in the compilation error:
duplicate 'const'
Of course, I can declare variable like this:
const auto* ...
const auto* const...
But that way ties me close to pointers, i.e. it isn't a universal solution.
Is it possible to preserve true constancy, and, in the same time, provide flexibility (independency of the concrete type)?
There is experimental support for this utility called std::propagate_const in the Library Fundamentals v2. You can write a type trait on top of that that does this for you (if you do not have std::propagate_const you can consider writing it yourself :))
namespace {
template <typename T, typename = std::enable_if_t<true>>
PropagateConst {
using type = T;
};
template <typename T>
PropagateConst<T, std::enable_if_t<std::is_same<
decltype(*std::declval<std::decay_t<T>>()),
decltype(*std::declval<std::decay_t<T>>())>::value>> {
using type = std::propagate_const_t<std::decay_t<T>>;
};
template <typename T>
using PropagateConst_t = typename PropagateConst<T>::type;
template <typename Type>
decltype(auto) propagate_const(Type&& in) {
return PropagateConst_t<std::add_rvalue_reference_t<Type>>{in};
}
} // <anonymous>
// then use it like this
const auto result = propagate_const(RetrieveResult());
Note that the solution I have above only checks for the presence of an operator* in the possible pointer type. You might want to consider writing a more extensive test for that.
Also note that this uses reference collapsing in the propagate_const example so expect at least a move to happen in cases where you might be expecting elision. You can optimize it based on your use case. I just thought I would outline what was in my head. Maybe that would help
template<class T>
struct very_const_t { using type=T; };
template<class T>
struct very_const_t<T*> { using type=typename very_const_t<T>::type const*; };
template<class T>
struct very_const_t<T&> { using type=typename very_const_t<T>::type const&; };
template<class T>
typename very_const_t<T>::type&&
very_const( T&& t ) { return std::forward<T>(t); }
then:
const auto result = very_const(RetrieveResult());
note that this can block elision. I carefully do not block move semantics, however.
This does not move const into smart pointers. If you want that:
template<class T, class D>
struct very_const_t<std::unique_ptr<T,D>> { using type=std::unique_ptr<typename very_const_t<T>::type const, D>; };
template<class T>
struct very_const_t<std::shared_ptr<T>> { using type=std::shared_ptr<typename very_const_t<T>::type const>; };
will do it for unique and shared.
The subject is already touched in this boost-variant-ambiguous-construction question.
But my issue is not with types convertible to each other, but with completely unrelated types.
Simplified example:
// types not related in any way
class A {};
class B {};
class C {};
class D {};
using ABC_variant = boost::variant<A,B,C>;
using D_optional = boost::optional<D>;
The issue was related with the fact that optional on some type was not printable. But, completely unrelated output operator for some variant was trying to accept this boost::optional type (D_optional).
See:
std::ostream& operator << (std::ostream& os, const ABC_variant&)
{
return os << "ABC";
}
int main() {
D_optional dopt;
std::cout << dopt;
}
You can see on ideone - plenty of compilers errors saying that it does not know what do you want to print bool or ABC_variant and in case of ABC_variant it does not know how to convert D_optional to ABC_variant. As I understand that boost::optional is convertible to bool and first alternative is correct I have no idea why it tries to use ABC_variant conversion...
Furthermore I simplified this example even more and give up with boost::optional:
int main() {
D d;
std::cout << d;
}
Now, it does not have "bool alternative" and just complaining that it tries to construct ABC_variant from D:
prog.cpp:23:15: required from here
/usr/include/boost/variant/variant.hpp:1591:38: error: no matching
function for call to 'boost::variant::initializer::initialize(void*, D&)'
initializer::initialize(
This here is ostream operator for ABC_variant.
Of course I know that writing ostream operator for D/D_opt will solve the issue - but the problem is with diagnostic: if boost::variant did not accept any type as argument for its constructor, the compiler would tell me simple true - not this bunch of misleading sentences...
I doubt it is in such way by design - maybe there is some fixes ongoing?
Fortunately I and ideone uses the same compiler and boost: gcc4.9 and boost1.58.
I have created boost ticket for this problem. Just to clarify what is the real problem:
Real problem is with this boost.variant "converting" constructor accepting any type - there is no restriction, even so natural like that argument type should be convertible to any of this boost.variant instantiation types:
template <typename T>
variant(const T& operand)
{
convert_construct(operand, 1L);
}
My proposed solution can be something like this:
template <typename T, typename ...C>
struct IsAnyOf;
template <typename T, typename ...C>
struct IsAnyOf<T,T,C...> : std::true_type {};
template <typename T>
struct IsAnyOf<T> : std::false_type {};
template <typename T, typename C1, typename ...C>
struct IsAnyOf<T,C1,C...> : IsAnyOf<T, C...> {};
template <typename T,
typename EnableIf = typename std::enable_if<IsAnyOf<VariantType...>::value>::type>
variant(const T& operand)
But for now - the only solution is not to create any non template function accepting instantiation of boost::variant. So either create function template or aggregate instantiation of boost::variant in some struct type.
So either this:
template <typename T>
typename std::enable_if<std::is_same<T,ABC_variant>::value, std::ostream&>::type
operator << (std::ostream& os, const T&)
{
return os << "ABC";
}
Or something like this:
struct ABC_variant
{
boost::variant<A,B,C> v;
ABC_variant(const A&);
ABC_variant(const B&);
ABC_variant(const C&);
};
The issue is fixed in boots.1.62
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.