Why does Boost MPL have integral constants? - c++

Since you can take integral values as template parameters and perform arithmetic on them, what's the motivation behind boost::mpl::int_<> and other integral constants? Does this motivation still apply in C++11?

You can take integral values as template parameters, but you cannot take both types and non-type template parameters with a single template. Long story short, treating non-type template parameters as types allows for them to be used with a myriad of things within MPL.
For instance, consider a metafunction find that works with types and looks for an equal type within a sequence. If you wished to use it with non-type template parameters you would need to reimplement new algorithms 'overloads', a find_c for which you have to manually specify the type of the integral value. Now imagine you want it to work with mixed integral types as the rest of the language does, or that you want to mix types and non-types, you get an explosion of 'overloads' that also happen to be harder to use as you have to specify the type of each non-type parameter everywhere.
This motivation does still apply in C++11.
This motivation will still apply to C++y and any other version, unless we have some new rule that allows conversion from non-type template parameters to type template parameters. For instance, whenever you use 5 and the template requests a type instantiate it with std::integral_constant< int, 5 > instead.

tldr; Encoding a value as a type allows it to be used in far more places than a simple value. You can overload on types, you can't overload on values.
K-Ballo's answer is great.
There's something else I think is relevant though. The integral constant types aren't only useful as template parameters, they can be useful as function arguments and function return types (using the C++11 types in my examples, but the same argument applies to the Boost ones that predate them):
template<typename R, typename... Args>
std::integral_constant<std::size_t, sizeof...(Args)>
arity(R (*)(Args...))
{ return {}; }
This function takes a function pointer and returns a type telling you the number of arguments the function takes. Before we had constexpr functions there was no way to call a function in a constant expression, so to ask questions like "how many arguments does this function type take?" you'd need to return a type, and extract the integer value from it.
Even with constexpr in the language (which means the function above could just return sizeof...(Args); and that integer value would be usable at compile time) there are still good uses for integral constant types, e.g. tag dispatching:
template<typename T>
void frobnicate(T&& t)
{
frob_impl(std::forward<T>(t), std::is_copy_constructible<T>{});
}
This frob_impl function can be overloaded based on the integer_constant<bool, b> type passed as its second argument:
template<typename T>
void frob_impl(T&& t, std::true_type)
{
// do something
}
template<typename T>
void frob_impl(T&& t, std::false_type)
{
// do something else
}
You could try doing something similar by making the boolean a template parameter:
frob_impl<std::is_copy_constructible<T>::value>(std::forward<T>(t));
but it's not possible to partially specialize a function template, so you couldn't make frob_impl<true, T> and frob_impl<false, T> do different things. Overloading on the type of the boolean constant allows you to easily do different things based on the value of the "is copy constructible" trait, and that is still very useful in C++11.
Another place where the constants are useful is for implementing traits using SFINAE. In C++03 the conventional approach was to have overloaded functions that return two types with different sizes (e.g an int and a struct containing two ints) and test the "value" with sizeof. In C++11 the functions can return true_type and false_type which is far more expressive, e.g. a trait that tests "does this type have a member called foo?" can make the function indicating a positive result return true_type and make the function indicating a negative result return false_type, what could be more clear than that?
As a standard library implementor I make very frequent use of true_type and false_type, because a lot of compile-time "questions" have true/false answers, but when I want to test something that can have more than two different results I will use other specializations of integral_constant.

Related

C++Concepts: How to enforce a method to accept a constrained type [duplicate]

I'm trying to write a C++20 concept to express the requirement that a type have a certain method, which takes an argument, but for the purposes of this concept I don't care what the argument type is.
I've tried to write something like:
template <typename T>
concept HasFooMethod = requires(T t, auto x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
however, both gcc and clang reject this, giving an error that 'auto' cannot be used in the parameter list of a requires expression this way.
An alternative would be to put the type of 'x' as a second template parameter:
template <typename T, typename TX>
concept HasFooMethod = requires(T t, TX x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
but then this requires TX to be specified explicitly whenever the concept is used, it cannot be deduced:
struct S { void Foo(int); };
static_assert(HasFooMethod<S>); // doesn't compile
static_assert(HasFooMethod<S, int>); // the 'int' must be specified
Is there any way to write a concept that allows Foo to take an argument of unspecified type?
The question Concept definition requiring a constrained template member function is very similar, but not the same: that question asks how to require that a (templated) method can take any type satisfying a given concept, while this question is about requiring that a method takes some particular type, although that type is unspecified. In terms of quantifiers, the other question is asking about (bounded) universal quantification while this one is about existential quantification. The other question's answer also does not apply to my case.
Concepts are not intended to provide the kind of functionality you are looking for. So they don't provide it.
A concept is meant to constrain templates, to specify a set of expressions or statements that a template intends to use (or at least be free to use) in its definition.
Within the template that you are so constraining, if you write the expression t.Foo(x), then you know the type of x. It is either a concrete type, a template parameter, or a name derived from a template parameter. Either way, the type of x is available at the template being constrained.
So if you want to constrain such a template, you use both the type of t and the type of x. Both are available to you at that time, so there is no problem with creating such a constraint. That is, the constraint is not on T as an isolated type; it's on the association between T and X.
Concepts aren't meant to work in a vacuum, devoid of any association with the actual place of usage of the constraint. You shouldn't focus on creating unary concepts so that users can static_assert their classes against them. Concepts aren't meant for testing if a type fulfills them (which is basically what your static_assert is doing); they're meant for constraining the template definition that uses them.
Your constraint needs to be FooCallableWith, not HasFooMethod.
Something close to this can be accomplished by defining an adapter type that can implicitly convert to (almost) anything:
struct anything
{
// having both these conversions allows Foo's argument to be either
// a value, an lvalue reference, or an rvalue reference
template <typename T>
operator T&();
template <typename T>
operator T&&();
};
Note that these operators do not need to be implemented, as they will only be used in an unevaluated context (and indeed, they could not be implemented for all types T).
Then, HasFooMethod can be written as:
template <typename T>
concept HasFooMethod = requires(T t, anything a)
{
{ t.Foo(a) } -> std::same_as<void>;
};

How can unspecified types be used in C++20 'requires' expressions?

I'm trying to write a C++20 concept to express the requirement that a type have a certain method, which takes an argument, but for the purposes of this concept I don't care what the argument type is.
I've tried to write something like:
template <typename T>
concept HasFooMethod = requires(T t, auto x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
however, both gcc and clang reject this, giving an error that 'auto' cannot be used in the parameter list of a requires expression this way.
An alternative would be to put the type of 'x' as a second template parameter:
template <typename T, typename TX>
concept HasFooMethod = requires(T t, TX x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
but then this requires TX to be specified explicitly whenever the concept is used, it cannot be deduced:
struct S { void Foo(int); };
static_assert(HasFooMethod<S>); // doesn't compile
static_assert(HasFooMethod<S, int>); // the 'int' must be specified
Is there any way to write a concept that allows Foo to take an argument of unspecified type?
The question Concept definition requiring a constrained template member function is very similar, but not the same: that question asks how to require that a (templated) method can take any type satisfying a given concept, while this question is about requiring that a method takes some particular type, although that type is unspecified. In terms of quantifiers, the other question is asking about (bounded) universal quantification while this one is about existential quantification. The other question's answer also does not apply to my case.
Concepts are not intended to provide the kind of functionality you are looking for. So they don't provide it.
A concept is meant to constrain templates, to specify a set of expressions or statements that a template intends to use (or at least be free to use) in its definition.
Within the template that you are so constraining, if you write the expression t.Foo(x), then you know the type of x. It is either a concrete type, a template parameter, or a name derived from a template parameter. Either way, the type of x is available at the template being constrained.
So if you want to constrain such a template, you use both the type of t and the type of x. Both are available to you at that time, so there is no problem with creating such a constraint. That is, the constraint is not on T as an isolated type; it's on the association between T and X.
Concepts aren't meant to work in a vacuum, devoid of any association with the actual place of usage of the constraint. You shouldn't focus on creating unary concepts so that users can static_assert their classes against them. Concepts aren't meant for testing if a type fulfills them (which is basically what your static_assert is doing); they're meant for constraining the template definition that uses them.
Your constraint needs to be FooCallableWith, not HasFooMethod.
Something close to this can be accomplished by defining an adapter type that can implicitly convert to (almost) anything:
struct anything
{
// having both these conversions allows Foo's argument to be either
// a value, an lvalue reference, or an rvalue reference
template <typename T>
operator T&();
template <typename T>
operator T&&();
};
Note that these operators do not need to be implemented, as they will only be used in an unevaluated context (and indeed, they could not be implemented for all types T).
Then, HasFooMethod can be written as:
template <typename T>
concept HasFooMethod = requires(T t, anything a)
{
{ t.Foo(a) } -> std::same_as<void>;
};

C++ template metaprogramming: how to deduce type in expression pattern

I am want a static check of the parameter type of lambdas. I've written this code below and it seems to produce the correct result.
struct B { };
auto lamBc = [](B const& b) { std::cout << "lambda B const" << std::endl; };
template<typename ClosureType, typename R, typename Arg>
constexpr auto ArgType(R (ClosureType::*)(Arg) const)->Arg;
template <typename T>
using ArgType_t = decltype(ArgType(&T::operator()));
// ArgType_t<lamBc> is "reference to B const"
However, I noticed that, for example, the standard library uses class template specialization to extract the referred-to type from a reference type in std::remove_reference. So I tried that approach and it also seems to produce the correct result.
template<typename L>
struct ArgType2;
template<typename ClosureType, typename R, typename Arg>
struct ArgType2<R (ClosureType::*)(Arg) const>
{
typedef Arg type;
};
template <typename T>
using ArgType2_t = typename ArgType2<decltype(&T::operator())>::type;
// ArgType2_t<lamBc> is also "reference to B const"
My questions are: Which is the standard way to extract types from a pattern expression? What are the trade-offs in either approach?
Both your approaches are valid, interchangeable and lead to the same result (deduce the type of the parameter lambda accepts).
For type traits it is required by the standard (see 23.15.1 Requirements) that:
A UnaryTypeTrait describes a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the property being described. ...
A BinaryTypeTrait describes a relationship between two types. It shall be a class template that takes two template type arguments
and, optionally, additional arguments that help define the
relationship being described. ...
A TransformationTrait modifies a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the modification. ...
I suppose that this requirement appeared mostly for historical reasons as decltype functionality was introduced after type traits had been proposed (and these type traits were based on type traits from boost which had been created even earlier, see, for example, this).
Also, note, that class templates are more flexible for general purpose type traits than the logic based on functions declarations and decltype.
The main point is that with C++11 and later in your particular case you are free to use the way which is the most convenient and reflects the programming logic better.
They are both "standard", the decltype() way is simply available in modern C++ variants, the PTS method was the only way to do this sort of things under the original C++ standard.

How does Eric Niebler's implementation of std::is_function work?

Last week Eric Niebler tweeted a very compact implementation for the std::is_function traits class:
#include <type_traits>
template<int I> struct priority_tag : priority_tag<I - 1> {};
template<> struct priority_tag<0> {};
// Function types here:
template<typename T>
char(&is_function_impl_(priority_tag<0>))[1];
// Array types here:
template<typename T, typename = decltype((*(T*)0)[0])>
char(&is_function_impl_(priority_tag<1>))[2];
// Anything that can be returned from a function here (including
// void and reference types):
template<typename T, typename = T(*)()>
char(&is_function_impl_(priority_tag<2>))[3];
// Classes and unions (including abstract types) here:
template<typename T, typename = int T::*>
char(&is_function_impl_(priority_tag<3>))[4];
template <typename T>
struct is_function
: std::integral_constant<bool, sizeof(is_function_impl_<T>(priority_tag<3>{})) == 1>
{};
But how does it work?
The general idea
Instead of listing all the valid function types, like the sample implementation over on cpprefereence.com, this implementation lists all of the types that are not functions, and then only resolves to true if none of those is matched.
The list of non-function types consists of (from bottom to top):
Classes and unions (including abstract types)
Anything that can be returned from a function (including void and reference types)
Array types
A type that does not match any of those non-function types is a function type. Note that std::is_function explicitly considers callable types like lambdas or classes with a function call operator as not being functions.
is_function_impl_
We provide one overload of the is_function_impl function for each of the possible non-function types. The function declarations can be a bit hard to parse, so let's break it down for the example of the classes and unions case:
template<typename T, typename = int T::*>
char(&is_function_impl_(priority_tag<3>))[4];
This line declares a function template is_function_impl_ that takes a single argument of type priority_tag<3> and returns a reference to an array of 4 chars. As is customary since the ancient days of C, the declaration syntax gets horribly convoluted by the presence of array types.
This function template takes two template arguments. The first is just an unconstrained T, but the second is a pointer to a member of T of type int. The int part here does not really matter, ie. this will even work for Ts that do not have any members of type int. What it does though is that it will result in a syntax error for Ts that are not of class or union type. For those other types, attempting to instantiate the function template will result in a substitution failure.
Similar tricks are used for the priority_tag<2> and priority_tag<1> overloads, which use their second template arguments to form expressions that only compile for Ts being valid function return types or array types respectively. Only the priority_tag<0> overload does not have such a constraining second template parameter and thus can be instantiated with any T.
All in all we declare four different overloads for is_function_impl_, which differ by their input argument and return type. Each of them takes a different priority_tag type as argument and returns a reference to a char array of different unique size.
Tag dispatching in is_function
Now, when instantiating is_function, it instantiates is_function_impl with T. Note that since we provided four different overloads for this function, overload resolution has to take place here. And since all of these overloads are function templates, that means SFINAE has a chance to kick in.
So for functions (and only functions) all of the overloads will fail except the most general one with priority_tag<0>. So why doesn't instantiation always resolve to that overload, if it's the most general one? Because of the input arguments of our overloaded functions.
Note that priority_tag is constructed in such a way that priority_tag<N+1> publicly inherits from priority_tag<N>. Now, since is_function_impl is invoked here with priority_tag<3>, that overload is a better match than the others for overload resolution, so it will be tried first. Only if that fails due to a substitution error the next-best match is tried, which is the priority_tag<2> overload. We continue in this way until we either find an overload that can be instantiated or we reach priority_tag<0>, which is not constrained and will always work. Since all of the non-function types are covered by the higher prio overloads, this can only happen for function types.
Evaluating the result
We now inspect the size of the type returned by the call to is_function_impl_ to evaluate the result. Remember that each overload returns a reference to a char array of different size. We can therefore use sizeof to check which overload was selected and only set the result to true if we reached the priority_tag<0> overload.
Known Bugs
Johannes Schaub found a bug in the implementation. An array of incomplete class type will be incorrectly classified as a function. This is because the current detection mechanism for array types does not work with incomplete types.

Reason for using non-type template parameter instead of regular parameter?

In C++ you can create templates using a non-type template parameter like this:
template< int I >
void add( int& value )
{
value += I;
}
int main( int argc, char** argv )
{
int i = 10;
add< 5 >( i );
std::cout << i << std::endl;
}
Which prints "15" to cout. What is the use for this? Is there any reason for using a non-type template parameter instead of something more conventional like:
void add( int& value, int amount )
{
value += amount;
}
Sorry if this has already been asked (I looked but couldn't find anything).
There are many applications for non-type template arguments; here are a few:
You can use non-type arguments to implement generic types representing fixed-sized arrays or matrices. For example, you might parameterize a Matrix type over its dimensions, so you could make a Matrix<4, 3> or a Matrix<2, 2>. If you then define overloaded operators for these types correctly, you can prevent accidental errors from adding or multiplying matrices of incorrect dimensions, and can make functions that explicitly communicate the expected dimensions of the matrices they accept. This prevents a huge class of runtime errors from occur by detecting the violations at compile-time.
You can use non-type arguments to implement compile-time function evaluation through template metaprogramming. For example, here's a simple template that computes factorial at compile-time:
template <unsigned n> struct Factorial {
enum {
result = n * Factorial<n - 1>::result
};
};
template <> struct Factorial<0> {
enum {
result = 1
};
};
This allows you to write code like Factorial<10>::result to obtain, at compile-time, the value of 10!. This can prevent extra code execution at runtime.
Additionally, you can use non-type arguments to implement compile-time dimensional analysis, which allows you to define types for kilograms, meters, seconds, etc. such that the compiler can ensure that you don't accidentally use kilograms where you meant meters, etc.
Hope this helps!
You're probably right in this case, but there are cases where you need to know this information at compile time:
But how about this?
template <std::size_t N>
std::array<int, N> get_array() { ... }
std::array needs to know its size at compile time (as it is allocated on the stack).
You can't do something like this:
std::array<int>(5);
Well, this the typical choice between compile-time polymorphism and run-time polymorphism.
From the wording of your question in appears that you see nothing unusual in "ordinary" template parameters, while perceiving non-type parameters as something strange and/or redundant. In reality the same issue can be applied to template type parameters (what you called "ordinary" parameters) as well. Identical functionality can often be implemented either through polymorphic classes with virtual functions (run-time polymorphism) or through template type parameters (compile-time polymorphism). One can also ask why we need template type parameters, since virtually everything can be implemented using polymorphic classes.
In case of non-type parameters, you might want to have something like this one day
template <int N> void foo(char (&array)[N]) {
...
}
which cannot be implemented with a run-time value.
In that particular instance, there's not really any advantage. But using template parameters like that, you can do a lot of things you couldn't do otherwise, like effectively bind variables to functions (like boost::bind), specify the size of a compile-time array in a function or class (std::array being a ready example of that), etc.
For instance, with that function, you write a function like
template<typename T>
void apply(T f) {
f(somenum);
}
Then you can pass apply a function:
apply(&add<23>);
That's an extremely simple example, but it demonstrates the principle. More advanced applications include applying functions to every value in a collection, calculating things like the factorial of a function at compile time, and more.
You couldn't do any of that any other way.
There are lots of reasons, like doing template metaprogramming (check Boost.MPL). But there is no need to go that far, C++11's std::tuple has an accessor std::get<i> that needs to be indexed at compile time, since the result is dependent on the index.
The most frequent use for a value parameter that I can think of is std::get<N>, which retrieves the Nth element of a std::tuple<Args...>. The second-most frequent use would be std::integral_constant and its main derivatives std::true_type and std::false_type, which are ubiquitous in any sort of trait classes. In fact, type traits are absolutely replete with value template parameters. In particular, there are SFINAE techniques which leverage a template of signature <typename T, T> to check for the existence of a class member.