What is the difference between Tuple and TypeTuple? I've looked at sample code in the library, but they look similar. How do I decide which to use? and is there a good reason why Tuple is in std.typecons but TypeTuple is in std.typetuple?
A Tuple is a data type, consisting of a collection of fields that you specify.
A TypeTuple is simply "a bunch of things" that the compiler knows about at compile time; it has no existence at run time.
(Contrary to its name, a TypeTuple can hold pretty much anything -- not just types!)
tuple std.typecons normal ordinary tuple of values.
typetuple in std.typetuple is tuple of types. It can be used at compile time like in this example function, where it limits allowed types for funciton to int, long and double only.
void foo (T) (T arg) {
static assert staticIndexOf!(T,TypeTuple!(int, long, double)) != -1,
T.stringof ~" is not allowed as argument for foo");
}
Tuple is a collection of variables (like a struct) while TypeTuple is a collection of type which you can use in template checks
Tuple!(int,"index",real,"value") var;
defines a variable with var.index a int and var.value a real
a TypeTuple is used when you want to examine whether the instantiations of your templates use the correct types
Related
I want to write a function template that accepts ranges of MyType-typed values, so I wrote
void f(const std::ranges::range auto& my_range) { /* ... */ }
Unfortunately this does not constrain the type of the values contained in the range. I could use a requires clause before the function body block but I want something reusable and not specific to this function.
Naturally I wrote
template <class T, class V>
concept range_of = std::ranges::range<T> && std::is_same_v<V, std::ranges::range_value_t<T>>;
void f(const range_of<MyType> auto& my_range) { /* ... */ }
but I'm very surprised that this is not supported out-of-the-box by the standard library given how natural it seems. This also applies to std::ranges::view for which I could write a similar view_of concept.
Is my definition of range_of incomplete or wrong? Or is there a good reason this isn't offered by the standard library?
The problem here is: what is the actual constraint that you want?
Do you want to:
constrain on the range's value type being specifically T?
constrain on the range's value type being convertible to T?
constrain on the range's value type satisfying some other concept, C?
any of the above but instead about the range's reference type?
Different contexts call for different versions of this. Your range_of concept is a perfectly fine implementation of the first one of these (could use std::same_as instead of std::is_same_v but doesn't super matter). But what happens when you want something else? The specific choice of constraint is going to depend very much on what it is you want to do.
So the direct answer is: there's no range_of concept because there's really no one true answer of what that concept should do.
A different answer would be that this isn't even what would be useful. What would be useful would be a direct way to pull out the associated types of a given range to make it easy to add further constraints on them.
For instance, if we take Rust, we can define a function that takes an arbitrary iterator:
fn foo<I: Iterator>(it: I) { ... }
That's sort of akin to just void f(range auto). It's a constraint, but not a very useful one. But Iterator, in Rust, has an associated type: its Item. So if you wanted an Iterator over a specific type, that's:
fn foo<I: Iterator<Item=i32>>(it: I) { ... }
If you wanted an Iterator whose type satisfies some other constraint:
fn foo<T: Debug, I: Iterator<Item=T>>(it: I) { ... }
And it's really this ability - to pull out associated types and constrain on them directly - that we really lack.
I have two functions which require the following:
Function 1: Requires the address of a variable to set the value. ( It knows about the correct type)
Function 2: Is a overloaded function which requires the value of a type.
I need a way to return a different types based on a enum (Which specifies type to use).
I tried to use std::get as you can use a number to specify the type.
However it requires SelectedType to be a constant expression which it is not.
std::variant<uint8_t,int8_t,uint16_t,int16_t,double,float> Var;
std::get<SelectedTypeEnum>(Var)
The point is to use one variable to avoid code repetition.
Consider the following code:
enum Type{
Type_uint8_t,
Type_int8_t,
Type_uint16_t,
Type_int16_t,
Type_std::string
} TypeList;
GetTypeToUse(Type&){ /* Get/Set the type to use */ }
void SetValueBasedOnEnum(Type TypeToUse,void* ptr) {/* Function 1: Sets the value of the type */}
// This is a Overloaded Function which supports all types in the enum.
//"T" represents the type.
void DoStuffWithDifferentTypes(T ValueOfType) { /*Function 2:*/ }
You cannot return a different type based on the value of an enumeration passed to the function. A functions signature is set at compile time so anything that would change it has to be a compile time construct.
If you have to return different types that you can only know at run time then you can use a std::variant or std::any for that. std::variant is basically a tagged union so you have to specify which types it can hold. If you have a bounded set of types, this the the preferred data structure. If you have an unbounded set of types, then you can use std::any. It uses type erasure and dynamic memory allocation so it is a lot more expensive to use than a std::variant but that is the cost you have to pay to get unlimited flexibility.
Another option, if it makes sense for you use case, is to have all the types inherit from a common base type. Then you can return a pointer to base from the function but work with the object polymorphicly.
tuple <int, string, int> x=make_tuple(1, "anukul", 100);
cout << x[0]; //1
cout << get<0>(x); //2
2 works. 1 does not.
Why is it so?
From Lounge C++ I learnt that it is probably because the compiler does not know what data type is stored at that index.
But it did not make much sense to me as the compiler could just look up the declaration of that tuple and determine the data type or do whatever else is done while accessing other data structures' elements by index.
Because [] is an operator (named operator[]), thus a member function, and is called at run-time.
Whereas getting the tuple item is a template mechanism, it must be resolved at compile time. Which means this can be only done with the <> templating syntax.
To better understand, a tuple may store different types. A template function may return different types depending on the index passed, as this is resolved at compile time.
The operator[] must return a unique type, whatever the value of the passed parameter is. Thus the tuple functionality is not achievable.
get<0>(x) and get<1>(x) are two different functions generated at compile time, and return different types. The compiler generates in fact two functions which will be mangled to something like
int get_tuple_int_string_int_0(x)
and
string get_tuple_int_string_int_1(x)
The other answers here address the issue of why this isn't possible to implement, but it's also worth asking the question of whether it should be possible. (The answer is no.)
The subscript operator [] is semantically supposed to indicate dynamically-resolved access to a element of a collection, such as an array or a list (of any implementation). The access pattern generally implies certain things: the number of elements probably isn't known to the surrounding code, which element is being accessed will probably vary at runtime, and the elements are all of the same observable type (thus, to the calling code, interchangeable).
Thing is, a tuple isn't (that kind of) a collection. It's actually an anonymous struct, and its elements aren't interchangeable slots at all - semantically, they are regular fields. What's probably throwing you off is that they happen to be labelled with numbers, but that's really just an anonymous naming pattern - analogous to accessing the elements as x._0, x._1, etc. (The fact you can compute the field names at compile-time is a coincidental bonus enabled by C++'s type system, and is not fundamentally related to what a tuple is; tuples, and this answer, are not really specific to C++.)
So it doesn't support operator[] for the same reason that plain old structs don't support operator[]: there's no semantically-valid use for it in this context. Structures have a fixed set of fields that aren't interchangeable or dynamically computable, and since the tuple is a structure, not a collection, it follows the same rule. Its field names just look different.
It can be supported, it just needs to take a compile-time index. Since parameters of a function cannot be made constexpr, we need to wrap the index within a type and pass that instead. (e.g. std::integral_constant<std::size_t, N>.
The following is an extension of std::tuple that supports operator[].
template <typename... Ts>
class tuple : public std::tuple<Ts...> {
public:
using std::tuple<Ts...>::tuple;
template <std::size_t N>
decltype(auto) operator[](std::integral_constant<std::size_t, N>) {
return std::get<N>(*this);
}
};
It would be used like so:
tuple<int, std::string> x(42, "hello");
std::cout << x[std::integral_constant<std::size_t, 0>{}] << std::endl;
// prints: 42
To mitigate the std::integral_constant crazy, we can use variable template:
template <std::size_t N>
std::integral_constant<std::size_t, N> ic;
With this, we can say:
std::cout << x[ic<1>] << std::endl; // prints: hello
So it could be done. One guess as to why this is currently not available is because features such as std::integral_constant and variable templates may not have existed at the time std::tuple was introduced. As to why it doesn't exist even though those features exist, I would guess it's because no one have yet to proposed it.
It's not very clean supporting operator[] given you can't vary the static return type to match the accessed element. If the Standard Library had incorporated something like boost::any or boost::variant, it would make more sense.
Put another way, if you write something like:
int n = atoi(argv[1]);
int x = x[n];
Then what should it do if n doesn't address an int member of the tuple? To even support checking you'd need to store some manner of RunTime Type Information for tuples, which is extra overhead in the executable/memory.
Containers that support the subscript operator (i.e., operator[]) like std::vector or std::array are collections of homogenous values. Whatever the index provided to the subscript operator is, the value to return is always of the same type. Therefore, those containers can define a member function with the following declaration:
T& operator[](int);
Where T is the type of every element in the collection.
On the other hand, an std::tupe is a collection of heterogeneous values. The return value of a hypothetical subscript operator for std::tuple needs to vary with the index. Therefore, its return type depends on the index.
In the declaration of the operator[] given above, the index is provided as a function argument and therefore may be determined at run time. However, the return type of the function is something that needs to be determined at compile time, not at run time.
Since the return type of such a function depends on the index but must be determined at compile-time, the solution is to define instead a function template that accepts the index as a (non-type) template parameter. This way, the index is provided as a compile-time constant and the return type is able to change with the index:
template<std::size_t I, class... Types>
typename std::tuple_element<I, tuple<Types...>>::type& get(tuple<Types...>&) noexcept;
As you can see, std::get's return type depends on the index, I:
std::tuple_element<I, tuple<Types...>>::type&
Because tuple has no operator "bracket".
Why is it so? You cannot resolve templates based only on the return value. You cannot write
template<typename T>
T tuple::operator [](size_t i) const ;
Which is absolutely necessary to be able to allow statements like x[0]
In my variable data, when running "add a variable" script code, how to define a generic container for all types? And what is the generic formula to access them? It's annoying because I have to define a vector template for each type (int float double etc). My variable should contain only and only a generic vector object, whatever it's int, or float or double etc. Is it possible? Any idea?
That's the whole point of the Standard Template Library..
std::vector<int>
std::vector<float>
Two vectors - the same class, templated with different types.
If you want a container of differing type you might want to look at std::tuple
If you want a single vector that contains objects of many different types, then you might want to use boost::any, or possibly boost::variant.
Edit:
oh, you want a container that can fit in any type? Yes you can. But within certain restrictions.
See boost::any and boost::variant. boost::variant would enable you to save data of several types enumerated when declaring the boost::variant. boost::any doesn't make you enumerate all types you want to support, but you need to cast them to get back the value yourself.
In short, you must either store the type information somewhere else ( when using boost::any ), or just support a few types (say, a heterogeneous vector that supports int and double using boost::variant)
template in C++ works exactly by eliminating the need to write the same class for every type.
For example:
// function template
template <class T>
T GetMax (T a, T b) {
T result;
result = (a>b)? a : b;
return (result);
}
this GetMax should work for whatever type that has a > operator. So that is exactly what template is for in C++.
If you need more help on implementing a vector on C++ (which, by the way, is not so simple when it comes to custom types that has its own constructor and destructor. You may need allocator to get un-initialized space), read this (Implementation of Vector in C++).
In Javascript or ActionScript it's possible to pass an object to a function or a constructor.
myfunction({myParam:1, myOtherParam:"hello"});
It is very useful when you have a lot of parameters to pass, IMO it makes using functions easier than using the classic approach.
myFunction(1,"hello");
Is there something similar in C++?
TIA
boost parameter http://www.boost.org/doc/libs/release/libs/parameter/ do exactly what you want.
From its abstract:
Use this library to write functions and class templates that can
accept arguments by name
Small example:
// include boost parameter
#include <boost/parameter/keyword.hpp>
namespace parameter = boost::parameter;
// first declare named parameters
BOOST_PARAMETER_NAME(a) // Note: no semicolon
BOOST_PARAMETER_NAME(b)
// then declare your function
BOOST_PARAMETER_FUNCTION(
(int), // 1. parenthesized return type
my_function, // 2. name of the function
tag, // 3. namespace of tag types (don't change!)
(required (a, int) ) // 4. one required parameter of type int
(optional // and an optional parameters, with default value
(b, int, 0)
)
)
{
return a + b;
}
// then you can call it with no named parameters
int result = my_function(1, 2);
// or with named parameters
int result = my_function(_a=1, _b=2);
// also with optional parameters omitted
int result = my_function(_a=3);
You can use the "named parameter idiom":
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.20
Which would make your call look like:
f(1).myOtherParam("Hello")
See here for a comparison with Boost parameter.
One could use structures:
struct foo {
int a,b,c;
float f;
}
Sadly, you need to define them somewhere and the receiving function needs to accept them, you can't just make them up in-place.
At the end of the day, there's no language tool in C++ that could mimic the JavaScript 'idiom'. Such stuff lies in the nature of a dynamic language, which C++ is not.
Yes.
In C++, an object is an instance of a class. You could create a class holding all the possible arguments, instantiate it and fill it with your particular values, and then pass that instance to the function.
You cannot just pass an arbitrary object instead of the function's arguments, because C++ doesn't have named arguments - only the position matters, and the position within some kind of hash structure is lost. So you can't say foo(y=3) when you have a function foo(int x, int y) because the names x and y only have meaning within the function - not to its callers.
No, not really. There is a map class in the standard library, and of course you could write a function that accepted a map full of named values as input, but there's nothing that exists directly as a language feature equivalent to what you've shown.
As several other posters have pointed out, of course you can define a class to hold all the data values, but this just pushes the ordered parameter list from the function to the constructor of that object, so it buys you nothing at all.
Use structs or classes to group your data.
If you're looking for a way to pass key value pairs, use STL maps
Not at the language level, but:
It is very useful when you have a lot of parameters to pass, IMO it makes using functions easier than using the classic approach.
You should really consider cutting down on your parameters if you can. Often this can be achieved by using aggregates:
Example:
draw_rectangle(x1, y1, x2, y2, r, g, b, a)
Could be reduced to:
draw_rectangle(p1, p2, color)
Or even further:
draw_rectangle(rect, color)
The temptation for named parameters should be mitigated considerably if you do this.
You can also use alternative approaches like Boost Parameter which, through a lot of template magic, accomplishes something like this. However, it requires you turn all your functions using this technique into templates written in a very precise way, and it's a very bulky and heavy-handed attempt to force the language to do something it wasn't designed to do if you ask me.
You can do the following, which supports default values to a limited amount (limited by the template system of C++). You will need to compile this with the newest standard (C++11)
// used to skip arguments and default to the previously specified value
struct UseDefault {
// empty intentionally!
};
// using this is optional, and only required if you want to provide default values by the CALLED function
template <typename T, T def> struct Default {
T value;
operator T() {
return value;
}
Default(T value) : value(value) {}
Default(UseDefault ignore) : value(def) {(void)ignore;}
};
// using tuple, you can bundle any number of parameters to one
int myFunc(std::tuple<Default<int,7>,Default<char,'x'>,std::string> parameters) {
std::cout << std::get<0>(parameters) << ", " << std::get<1>(parameters) << std::endl;
return 0;
}
You can then invoke myFunc like this:
func(std::make_tuple(6,UseDefault(),"hi"));
Note however, that there are some limitation to the template parameter types, for instance, you cannot pass strings (or char*s for that matter) as template parameters. However, if you only need reasonable basic default values, this could work.
Of course if you drop your requirement to specify default values, you can simply use the std::tuple without my Default type.