The struct Vec has all the requirements to be std::default_initializable. But the declaration is not finished, so it failed to compile.
template <std::default_initializable A>
struct It {};
struct Vec {
using Iterator = It<Vec>;
};
Is there some sort of workaround to keep the It requirement ?
In general, the answer to your question is no. If you want to make a member type alias, it has to be known at the time in question. And if the template you're trying to instantiate requires that the type it is given is complete (which default-initializable does), then it must be complete.
In your specific case however, it's not really necessary to make Iterator a member. If you want the iterator type for a range, the correct way to do that is to use ranges::iterator_t. And that meta-function will return the type that ranges::begin() returns.
Your begin member function can be specified to return auto, such that the definition of the function is what provides the It<Vec>, as follows:
template <std::default_initializable A>
struct It {};
struct Vec
{
auto begin() {return It<Vec>(...);}
};
That having been said, even if you want to define your iterator type outside of the container/range that it serves, it is still bound to that container/range type. Unless It is some kind of view or range transformation (and if it is, it probably shouldn't be default-constructing the range it modifies), It<UserType> shouldn't work. As such, constraining the It template is pointless; you know that Vec is default constructible because you wrote that class just below the iterator. If you want a sanity check, you can use a static_assert, but you don't need to constrain the template itself.
Related
I'm trying to define a C++ concept for standard library containers that allow push_back/emplace_back:
template <class ContainerType>
concept PushBackContainer = requires(ContainerType a)
{
requires SequenceContainer<ContainerType>;
{ a.push_back(typename ContainerType::const_reference& v) };
{ a.push_back(typename ContainerType::value_type&& v) };
// How do you define a variable templated function:
{ template< class... Args > a.emplace_back(Args&&... args) };
}
The problem I have is how do I define emplace_back with its variadic template arguments? I'm using Visual Studio 2019 but if this isn't supported I'd be interested in the correct syntax come the time it is.
Probably about the best that's worth doing is just a.emplace_back();.
Your push_back requirements don't have a correct syntax, either. I think you want:
template <class ContainerType>
concept PushBackContainer = requires(
ContainerType& a,
typename ContainerType::value_type const& cv,
typename ContainerType::value_type& v)
{
requires SequenceContainer<ContainerType>;
a.push_back(cv);
a.push_back(std::move(v));
a.emplace_back();
};
Requirements don't check for a function signature; they check for the validity of an expression (without instantiating more templates than necessary). If we had a class like:
class StrangeContainer {
public:
using value_type = std::string;
using const_reference = const value_type&;
private:
struct ValueHolder {
ValueHolder(const std::string& s) : value(s) {}
ValueHolder(std::string&& s) : value(std::move(s)) {}
std::string value;
};
public:
void push_back(ValueHolder);
template <typename ... Args>
void emplace_back(Args&&...);
};
then ignoring SequenceContainer requirements, PushBackContainer<StrangeContainer> would be true, and it would also satisfy the Standard's own requirements related to push_back. It satisfies the technical requirements, even though it has some surprising effects like the fact that push_back("") is ill-formed.
So for push_back, we're really just checking that it can be called with a const lvalue and with a non-const rvalue. (The Standard actually also requires that it can be called with a non-const lvalue and with a const rvalue, and these cases have the same behavior as when called with a const lvalue.)
(If you really wanted to test for an exact push_back signature, you could try static_cast<void (ContainerType::*)(typename ContainerType::value_type&&)>(&ContainerType::push_back); - but this is not recommended, since member functions in namespace std are not required to have signatures exactly as described, only to be callable with the same arguments as if declared as described.)
Also, the standard container class templates don't have any constraints on their push_back or emplace_back functions. Every instantiation of the templates which have push_back declares both overloads, whether or not the type is copyable and/or movable. If not, it would be an error to actually call or otherwise odr-use the push_back function, but it "exists" for purposes of requires-expressions and SFINAE contexts. Likewise, the emplace_back member template is declared to accept any number of arguments with any types and value categories, no matter whether they can be used as value_type constructor arguments or not.
So what we would want to test to find out if the container has an emplace_back with an essentially ordinary variadic function declaration would need to be phrased as: Can emplace_back be called with any number of arguments, with each having any possible type and each being either an lvalue or rvalue? I don't think there's any way to really answer that within C++, using requires-expressions, SFINAE tricks, or otherwise. So I would just do one simple test for existence of some sort of emplace_back, and that test might as well be as simple as possible: zero arguments.
You could get fancier and also test for some additional cases: Does emplace_back accept different numbers of arguments, up to some fixed maximum? Does it accept lvalue and rvalue arguments? Does it accept arguments of dummy struct types? Dummy struct types that aren't MoveConstructible? const, volatile, and const volatile types? All possible combinations of all of the above? But since you'll never cover all the cases, how much value does each partial enhancement like this really give, compared to the effort, complexity, and maintenance needed to add checks?
When using boost::any_range, what's the correct way of specifying that the underlying container (if any) shouldn't be modified?
E.g., with the alias
template<typename T>
using Range = boost::any_range<T, boost::forward_traversal_tag>;
to declare a range that isn't capable of modifying the contents of the underlying container or "data source", should it be declared as
const Range<T> myRange;
or as
Range<const T> myRange;
?
I suspect the first version is the correct one. But is it guaranteed to keep the constness of the container, if, for example, I apply any of the boost::adaptors?
Edit
From the documentation, apparently the range_iterator metafunction "deduces" the constness of the underlying container by declaring the range with const T instead of T. That is, range_iterator::<const T>::type is const_iterator (if the underlying container has such member type), instead of iterator, so the container can't be modified through this iterator.
Does that mean that Range<const T> also uses const_iterators to traverse the range?
Apparently the correct way to ensure that the values aren't modified is neither of those I mentioned.
From Boost.Range's documentation, we can see that any_range takes the following template parameters:
template<
class Value
, class Traversal
, class Reference
, class Difference
, class Buffer = any_iterator_default_buffer
>
class any_range;
I strongly suspect the way to declare a "const range" is to specify const T as the Reference type template parameter, although, surprisingly, I still haven't been able to find any explicit indication in the documentation that this is so.
So a const range could be declared as:
template<class C>
using ConstRange = boost::any_range<C, boost::forward_traversal_tag, const C, std::ptrdiff_t>
I have a class myClass that is templated, and I have it in mind to use it for two particular types.
The trouble is that whether or not something should be const in myClass depends on whether it is instantiated with the first type (in which pretty much everything is const) or the second type (in which pretty much everything is non-const).
How do I solve this problem? It seems there are two possible approaches.
I could write const in the templated code as if it were for the first type (the one that actually is const), and then somehow "throw away" all those consts once I instantiate with the second type? Is this possible?
The second approach is to not write const at all, and then when I instantiate myClass with the first type, I make the entire object itself const. This seems to make up a bit for the lack of const-correctness in the class implementation itself...
Or maybe I can do something else?
EDIT: Wait, no, the last approach wouldn't work, as I then wouldn't be able to call non-const methods....
Let's assume you have these two arbitrary types you want to instantiate your template class with, the first of which should trigger constness for your members:
struct RequiresConst
{};
struct OtherStruct
{};
You can then write some convenience templates like this:
template<class T, bool B>
using conditional_const = typename std::conditional<B, const T, T>::type;
template<class T>
constexpr bool needsConst = std::is_same_v<T, RequiresConst>;
This allows you to naturally spell out what you want:
template<class T>
struct MyClass
{
conditional_const<int, needsConst<T>> member;
};
Demo (including test).
Note that this only works for member variables. I'm not aware of a way to make functions const or non-const in a similarly convenient way. But you could write a const and non-const version for each function and enable exactly one of each pair via std::enable_if (or some other SFINAE).
It should also be mentioned that "this member should be const if the template parameter is this exact class" is a pretty odd requirement - not necessarily wrong but smelly. There is probably some specific trait that class has that you should check instead. But maybe your use case really only ever has the template instantiated for those two classes and the above will be sufficient.
Use a type_traits class.
Start with an empty typetraits class, then specialize it for your first type. Place there all the types you need with the const.
Then specialize it again for your second type, and place there the types without const.
Finally, in your templated class, use the type traits with the template type to select the types you need.
I know that getters are in general bad, but here, I just use one to illustrate a more general question.
Consider the following class:
template <class... T>
class my_tuple final
{
private:
std::tuple<T...> _data;
public:
template <class... U>
my_tuple(U&&... u)
: _data(std::forward<U>(u)...) {}
public:
template <std::size_t I>
auto get() -> decltype(std::get<I>(_data))
{return std::get<I>(_data);}
};
And consider that I cannot modify this class.
Is there a way, to write an external metafunction my_tuple_type (by external I mean a metafunction not belonging to the class) to actually get the type of the underlying tuple? (I tend to think that it is impossible if one of T... is a reference because just applying std::decay or std::remove_reference on the type returned by get will remove the original reference too).
EDIT: I have added a constructor to help testing.
EDIT2: For clarification, I cannot operate on T...: I am searching for a metafunction only based on the getter.
EDIT3: From the exterior of the class, I do not know the name of the underlying tuple member (here it is named _data, but it could be _tuple or whatever)
EDIT4: As an illustration, this can be achieved if we suppose that none of the types are references/pointers by:
1) Making a metafunction that will execute recursively the getter until it fails (so the tuple size N will be known)
2) Executing a std::decay on each type returned by std::get from 0 to N and putting them together.
But it will fail if one of the tuple element is a reference or pointer...
EDIT5: I will post an implementation of EDIT4 soon (I am working on that)
EDIT6: That is not an XY problem. The fundamental question I try to answer is:
consider a concept called Tuple_like whose only condition is to have a templated get member like here. The question is: from this only function get<I>(), is it possible to extract all information on the underlying tuple ?
No, std::get<I>(some_tuple&) is lossy. It returns the same type for references and value types. If there was a way to have an rvalue qualified call to get you could do it.
Well, there is pattern matching on the my_tuple type itself. And if you knew the name of the std::tuple field (or had a list of all possible names even) there are ways to violate privacy, which might work here. But I suspect those are excluded.
I have a class
template <typename Iterator, typename Value>
class Foo {
public:
Foo(const Iterator& it) { ... }
...
private:
map<Value, int> m_;
}
};
Is there any way to get rid of Value in the template? The Iterator may or may not be an STL iterator, but it's guaranteed that *it type is Value.
I know about iterator_traits<T>::value_type for STL iterators, but wonder if there's any way to get Value type automatically for an arbitrary Iterator type?
One trick I'm thinking about - say, we have a helper class
template <typename Iterator, typename Value>
class Bar {
public:
Bar(const Iterator& dummy_iterator, const Value& dummmy_value) {}
...
};
Then if we instantiate Bar as Bar(it, *it), the type of Value will be known inside Bar. But I can't find a good way to combine Bar with Foo.
Any iterator should provide iterator_traits<Iterator>::value_type. If it does not, then it is not an iterator. ISO C++ 2003 24.3.1[lib.iterator.traits] "Iterator traits":
To implement algorithms only in terms
of iterators, it is often necessary to
determine the value and difference
types that correspond to a particular
iterator type. Accordingly, it is
required that if Iterator is the type
of an iterator, the types
iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category
be defined as the iterator’s
difference type, value type and
iterator category, respectively.
Aside from that, there's no general way to obtain a type of an arbitrary C++ expression. C++0x will rectify it by providing decltype.
Sorry. The correct way to get rid of Value is to use iterator_traits as you suggested.
If your non-STL iterator is a naked pointer, then you get correct iterator_traits typedefs for free. Otherwise the non-STL iterator class must define the correct typedefs.
See the iterator traits documentation for more information.
As to getting value type of iterator previous answers were correct.
But there is more. The trick you are thinking of would not work with class. If Bar was a function like:
template <typename Iterator, typename Value>
void bar(const Iterator& dummy_iterator, const Value& dummmy_value) {}
then type deduction would work for bar(it, *it) and you would have the value type inside of bar. (But keep in mind that to use this trick you would still have to have a dereferencable iterator it which is not always good - how to deal with empty sequence then?)
Using a class Bar you would have to provide the template arguments Iterator and Value manually as there is no type deduction for classes and using Bar(it, *it) would no compile.