Deduction guide for the template class std::valarray<T> - c++

In the C++ Standard there is the following deduction guide for the template class std::valarray<T>:
template<class T, size_t cnt> valarray(const T(&)[cnt], size_t) -> valarray<T>;
However among the constructors of the class there is only the following appropriate constructor (or am I mistaken?)
valarray(const T&, size_t);
However if to run the following demonstrative program with a similar deduction guide
#include <iostream>
#include <utility>
template <typename T>
struct A
{
A( const T &, size_t ) { std::cout << "A<T>()\n"; }
};
template<class T, size_t cnt>
A(const T(&)[cnt], size_t) -> A<T>;
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
A obj( a, std::size( a ) );
}
the gcc compiler issues error
rog.cc:17:12: error: invalid conversion from 'int*' to 'int' [-fpermissive]
17 | A obj( a, std::size( a ) );
| ^
| |
| int*
prog.cc:7:8: note: initializing argument 1 of 'A<T>::A(const T&, size_t) [with T = int; size_t = long unsigned int]'
7 | A( const T &, size_t ) { std::cout << "A<T>()\n"; }
| ^~~~~~~~~
So a question arises whether it is a defect of the C++ Standard, or a bug of the compiler or I missed something.

Using the example given by https://en.cppreference.com/w/cpp/numeric/valarray/deduction_guides, we can look at the compiler output without optimizations to see which constructor is called:
int a[] = {1, 2, 3};
std::valarray va(a, 3);
https://godbolt.org/z/rtgeoi
main:
[...]
call std::valarray<int>::valarray(int const*, unsigned long)
[...]
C++ arrays decay to pointers to their first element very easily. However, without the deduction guide, the type deduced from the implicit guides would be std::valarray<int[3]> (the guide generated from valarray(const T&, size_t) wins because it does not need the array-to-pointer conversion). This can be demonstrated in your example, if we have both the A(const T&, std::size_t); and A(const T*, std::size_t); constructors:
template <typename T>
struct A
{
A(const T&, std::size_t);
A(const T*, std::size_t);
};
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
A obj(a, 10);
}
// Result:
call A<int [10]>::A(int const (&) [10], unsigned long)
https://godbolt.org/z/nlFlVT
Adding the deduction guide correctly deduces the intended int instead of int[10]: https://godbolt.org/z/efj557

However among the constructors of the class there is only the following appropriate constructor (or am I mistaken?)
There's also this one:
valarray( const T* vals, std::size_t count );
Which does match, when the array you pass in decays to a pointer, allowing the cppreference example to compile.

Related

Using static constexpr member array as pointer in template parameters

The following main.cpp illustrates the problem:
#include <type_traits>
template <class T, std::size_t N>
struct Array
{
T data_[N];
};
template <const std::size_t* EltArray, std::size_t EltCount>
struct Foo
{
};
int main()
{
// SIDE NOTE if arr is not declared static: the address of 'arr' is not a valid template argument
// because it does not have static storage duration
static constexpr std::size_t arr[3] = {1, 2, 3};
Foo<arr, 3> foo;// WORKING
static constexpr Array<std::size_t, 3> arr2 = {1, 2, 3};
static constexpr const std::size_t* arr2_ptr = arr2.data_;
Foo<arr2_ptr, 3> foo2;// ERROR:
// 'arr2_ptr' is not a valid template argument of type 'const size_t*'
// {aka 'const long long unsigned int*'} because
// 'arr2.Array<long long unsigned int, 3>::data_' is not a variable
static constexpr const std::size_t* test = std::integral_constant<const std::size_t*, arr2_ptr>{};// ERROR:
// 'arr2_ptr' is not a valid template argument of type 'const long long unsigned int*' because
// 'arr2.Array<long long unsigned int, 3>::data_' is not a variable
return 0;
}
I don't understand why arr2.data_ is not reusable just like arr. Can someone explain ?
I'm using gcc: mingw-w64\x86_64-8.1.0-posix-sjlj-rt_v6-rev0
g++.exe -Wall -std=c++2a -fconcepts -O2
I want to share the answer i just found in open-std and a compliant solution.
We all know that we cannot pass any variable as non type.
Did you know that we can pass a const reference to anything we want ?!
So the solution is:
#include <array>
// When passing std::array<std::size_t, EltCount> (by value), i get the error:
// 'struct std::array<long long unsigned int, EltCount>' is not a valid type for a template non-type parameter
template <std::size_t EltCount, const std::array<std::size_t, EltCount>& Elts>
struct Foo {};
static constexpr std::array<std::size_t, 3> arr = {1, 2, 3};
int main()
{
Foo<3, arr> foo;// WORKING
return 0;
}
And the answer to the initial question is:
quote of the N4296
14.3.2 Template non-type arguments [temp.arg.nontype]
For a non-type template-parameter of reference or pointer type, the
value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
(1.1) — a subobject (1.8),
Moral of the story: we can do what we want with references, not with pointers.

incorrect deduction of template parameter pack

The following program does not compile:
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
test<2, 3, true, false>(2, 1, {8, 8});
}
See it live on Coliru.
The error message
g++ -std=c++17 -O1 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:8:41: error: too many arguments to function 'void test(ParametersType&& ...)
[with unsigned int dim = 2; unsigned int N = 3; bool P = true; bool C = false; ParametersType = {}]'
8 | test<2, 3, true, false>(2, 1, {8, 8});
| ^
main.cpp:2:6: note: declared here
2 | void test(ParametersType&&... par)
| ^~~~
indicates that the parameter pack ParametersType... is deduced to an empty one, while I would expect it to be deduced according to the types of the arguments passed to test.
The problem is in the {8, 8} parameter passed to test.
Explicitly passing a std::array to the function solves the problem:
#include <array>
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
test<2, 3, true, false>(2, 1, std::array<int, 2>{8, 8});
}
See it live on Coliru.
Why does the compiler apparently incorrectly deduces the pack in the first example?
If the compiler is not able to deduce {8, 8} to an std::array, I would expect an "impossible to deduce" error. Why instead does the compiler deduce the pack to an empty one?
Template errors are hard to get right. It's just a quality of implementation. Clang for instances gives
main.cpp:2:6: note: candidate template ignored: substitution failure
[with dim = 2, N = 3, P = true, C = false]: deduced incomplete pack <int, int, (no value)>
for template parameter 'ParametersType'
which is easier to understand. And yes, unless using auto, {stuff} has no type.
From cppreference:
A braced-init-list is not an expression and therefore has no type,
e.g. decltype({1,2}) is ill-formed. Having no type implies that
template type deduction cannot deduce a type that matches a
braced-init-list, so given the declaration template void
f(T); the expression f({1,2,3}) is ill-formed.
You can also use auto in this context to fix your issue:
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
auto x = { 8, 8 };
test<2, 3, true, false>(2, 1, x);
}

Expression templates toy example: user-defined cast not applied for complex types

I am trying to build a toy example for expression trees using modern C++17 based on this blogpost. The code works fine for primitive types like int or double. However, when I try it with something like an Eigen::Vector3d the build fails because the user-defined cast operator result_t() const is not applied correctly (I assume).
Can someone give me a hint what exactly is the reason for the failure?
#include <Eigen/Dense>
template <class T, class U, class Callable>
struct BinaryExpression {
const T* left {nullptr};
const U* right {nullptr};
Callable callable;
BinaryExpression(const T& t, const U& u, const Callable c)
: left(&t), right(&u), callable(c) {}
auto operator()() const
{
return callable(*left, *right);
}
using result_t = decltype(std::declval<Callable>()(std::declval<const T&>(), std::declval<const U&>()));
operator result_t() const
{
return this->operator()();
}
};
struct Plus {
template <class T, class U>
auto operator()(const T& left, const U& right) const
{
return left + right;
}
};
int main()
{
Eigen::Vector3d v1 (1, 2, 3);
Eigen::Vector3d v2 (1, 2, 3);
int num1 = 1;
double num2 = 2.4;
BinaryExpression expr(num1, num2, Plus{});
BinaryExpression expr2(num2, expr, Plus{}); // this works fine
BinaryExpression expr3(v1, v2, Plus{});
BinaryExpression expr4(expr3, v1, Plus{}); // why does this give an error?
}
Compiler error message
../main.cpp: In instantiation of ‘auto Plus::operator()(const T&, const U&) const [with T = BinaryExpression<Eigen::Matrix<double, 3, 1>, Eigen::Matrix<double, 3, 1>, Plus>; U = Eigen::Matrix<double, 3, 1>]’:
.../main.cpp:36:55: required from ‘struct BinaryExpression<BinaryExpression<Eigen::Matrix<double, 3, 1>, Eigen::Matrix<double, 3, 1>, Plus>, Eigen::Matrix<double, 3, 1>, Plus>’
.../main.cpp:63:45: required from here
.../main.cpp:47:21: error: no match for ‘operator+’ (operand types are ‘const BinaryExpression<Eigen::Matrix<double, 3, 1>, Eigen::Matrix<double, 3, 1>, Plus>’ and ‘const Eigen::Matrix<double, 3, 1>’)
return left + right;
~~~~~^~~~~~~
I understand that operator+ is not defined for adding a BinaryExpression with a Matrix type. However, I expect the code to apply the user-defined cast of BinaryExpression which evaluates it to a Matrix and therefore calls the operator+ for adding two Matrix types.
line 47 is that they dont know the type of variable "left" and "right".
If you add an int with a string, it will produces error.

Eigen's AutoDiffJacobian, need some help getting a learning example to work

I have been using Eigen's AutoDiffScalar with much success and would now like to go over to the AutoDiffJacobian instead of doing this over by myself. Hence I created a learning example after have studied the AutoDiffJacobian.h, but something is wrong.
Functor:
template <typename Scalar>
struct adFunctor
{
typedef Eigen::Matrix<Scalar, 3, 1> InputType;
typedef Eigen::Matrix<Scalar, 2, 1> ValueType;
typedef Eigen::Matrix<Scalar,
ValueType::RowsAtCompileTime,
InputType::RowsAtCompileTime> JacobianType;
enum {
InputsAtCompileTime = InputType::RowsAtCompileTime,
ValuesAtCompileTime = ValueType::RowsAtCompileTime
};
adFunctor() {}
size_t inputs() const { return InputsAtCompileTime; }
void operator() (const InputType &input,
ValueType *output) const
{
Scalar s1 = Scalar(0), s2 = Scalar(0);
/* Some operations to test the AD. */
for (int i = 0; i < 3; i++)
{
s1 += log(input(i));
s2 += sqrt(input(i));
}
(*output)(0) = s1;
(*output)(1) = s2;
}
};
Usage:
Eigen::Matrix<double, 3, 1> in;
in << 1,2,3;
Eigen::Matrix<double, 2, 1> out;
Eigen::AutoDiffJacobian< adFunctor<double> > adjac;
adjac(in, &out);
The error that is received from this as is follows:
/usr/include/eigen3/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h: In instantiation of ‘void Eigen::AutoDiffJacobian<Functor>::operator()(const InputType&, Eigen::AutoDiffJacobian<Functor>::ValueType*, Eigen::AutoDiffJacobian<Functor>::JacobianType*) const [with Functor = adFunctor<double>; Eigen::AutoDiffJacobian<Functor>::InputType = Eigen::Matrix<double, 3, 1>; Eigen::AutoDiffJacobian<Functor>::ValueType = Eigen::Matrix<double, 2, 1>; Eigen::AutoDiffJacobian<Functor>::JacobianType = Eigen::Matrix<double, 2, 3, 0, 2, 3>]’:
/home/emifre/Git/autodiff-test/src/autodiff_test.cpp:55:17: required from here
/usr/include/eigen3/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h:69:24: error: no matching function for call to ‘Eigen::AutoDiffJacobian<adFunctor<double> >::operator()(Eigen::AutoDiffJacobian<adFunctor<double> >::ActiveInput&, Eigen::AutoDiffJacobian<adFunctor<double> >::ActiveValue*) const’
Functor::operator()(ax, &av);
~~~~~~~~~~~~~~~~~~~^~~~~~~~~
/home/emifre/Git/autodiff-test/src/autodiff_test.cpp:27:8: note: candidate: void adFunctor<Scalar>::operator()(const InputType&, adFunctor<Scalar>::ValueType*) const [with Scalar = double; adFunctor<Scalar>::InputType = Eigen::Matrix<double, 3, 1>; adFunctor<Scalar>::ValueType = Eigen::Matrix<double, 2, 1>]
void operator() (const InputType &input,
^~~~~~~~
/home/emifre/Git/autodiff-test/src/autodiff_test.cpp:27:8: note: no known conversion for argument 2 from ‘Eigen::AutoDiffJacobian<adFunctor<double> >::ActiveValue* {aka Eigen::Matrix<Eigen::AutoDiffScalar<Eigen::Matrix<double, 3, 1> >, 2, 1, 0, 2, 1>*}’ to ‘adFunctor<double>::ValueType* {aka Eigen::Matrix<double, 2, 1>*}’
From this error it seems that I am somehow not having the correct types for my functor for the second call to the functor in AutoDiffJacobian.h, but the first call to it works.
I hope someone here has an idea why and can help, maybe I have just misunderstood the usage.
EDIT: A compilable example that shows the problem:
#include <Eigen/Dense>
#include <unsupported/Eigen/AutoDiff>
/*
* Testing differentiation that will produce a Jacobian, using functors and the
* AutoDiffJacobian helper.
*/
template <typename Scalar>
struct adFunctor
{
typedef Eigen::Matrix<Scalar, 3, 1> InputType;
typedef Eigen::Matrix<Scalar, 2, 1> ValueType;
typedef Eigen::Matrix<Scalar,
ValueType::RowsAtCompileTime,
InputType::RowsAtCompileTime> JacobianType;
enum {
InputsAtCompileTime = InputType::RowsAtCompileTime,
ValuesAtCompileTime = ValueType::RowsAtCompileTime
};
adFunctor() {}
size_t inputs() const { return InputsAtCompileTime; }
void operator() (const InputType &input,
ValueType *output) const
{
Scalar s1 = Scalar(0), s2 = Scalar(0);
/* Some operations to test the AD. */
for (int i = 0; i < 3; i++)
{
s1 += log(input(i));
s2 += sqrt(input(i));
}
(*output)(0) = s1;
(*output)(1) = s2;
}
};
int main(int argc, char *argv[])
{
Eigen::Matrix<double, 3, 1> in;
in << 1,2,3;
Eigen::Matrix<double, 2, 1> out;
Eigen::AutoDiffJacobian< adFunctor<double> > adjac;
adjac(in, &out);
return 0;
}
Okey, after a lot of testing I got it to work.
It was just me misunderstanding the error from the compiler that said it straight out, I was missing the template for the operator itself.
It just needs to be changed to:
template <typename T1, typename T2>
void operator() (const T1 &input, T2 *output) const
Now it works like a treat! I hope someone more than me has usage of this.
Maybe that is too late for a reply.
I post my solution here.
The reason why compile failed is that inside AutoDiffScalar template class, it requires the custom function to implement the operator() with arguments are Vectors with ActiveScalar as scalars. Calling custom function inside AutoDiffJacobian - ActiveType overload
The ActiveScalar is a AutoDiffScalar<...> type.
Therefore, the custom class must provide an overload of operators () that accept such arguments.
Besides, they also require an overload that accepts raw InputType/ValueType. Calling custom function inside AutoDiffJacobian - OriginalType overload
Then, to have both of them, it is better to have a template implementation, e.g.,
template<typename T>
void operator()(const Eigen::Matrix<T, InputsAtCompileTime, 1>& x,
Eigen::Matrix<T, ValuesAtCompileTime,1>* v) const{
// Computation codes here ...
}
This is better than the solution from #Korken which accepts any type.

Simple constexpr function failed to compile with GCC (clang is OK)

The following code does not compile with GCC 5.2 (C++14). It does compile with clang 3.6 (C++14). (original code can be found here)
#include <cstddef>
#include <algorithm>
#include <type_traits>
#include <utility>
template <typename T>
class aggregate_wrapper;
template <typename T, std::size_t n>
class aggregate_wrapper<T[n]> {
public:
using array = T[n];
template <typename... Ts, typename = decltype(array{std::declval<Ts>()...})>
aggregate_wrapper(Ts&&... xs)
: arr_{std::forward<Ts>(xs)...} {
// nop
}
aggregate_wrapper(const array& arr) {
std::copy(arr, arr + n, arr_);
}
aggregate_wrapper(array&& arr) {
std::move(arr, arr + n, arr_);
}
operator T* () {
return arr_;
}
operator const T* () const {
return arr_;
}
constexpr std::size_t size() const {
return n;
}
private:
array arr_;
};
int main() {
aggregate_wrapper<int[3]> arr;
static_assert(arr.size() == 3, "");
}
The error message produced is
main.cpp: In function 'int main()':
main.cpp:44:3: error: non-constant condition for static assertion
static_assert(arr.size() == 3, "");
^
main.cpp:44:25: error: call to non-constexpr function 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]'
static_assert(arr.size() == 3, "");
^
main.cpp:34:25: note: 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]' is not usable as a constexpr function because:
constexpr std::size_t size() const {
^
main.cpp:34:25: error: enclosing class of constexpr non-static member function 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]' is not a literal type
main.cpp:10:7: note: 'aggregate_wrapper<int [3]>' is not literal because:
class aggregate_wrapper<T[n]> {
^
main.cpp:10:7: note: 'aggregate_wrapper<int [3]>' is not an aggregate, does not have a trivial default constructor, and has no constexpr constructor that is not a copy or move constructor
Any ideas? Should the code compile according to the standard?
Or you could just make your existing variadic constructor serve as your constexpr constructor to perform the default construction:
template <typename... Ts, typename = decltype(array{std::declval<Ts>()...})>
constexpr // <---- ADD THIS
aggregate_wrapper(Ts&&... xs)
: arr_{std::forward<Ts>(xs)...} {
// nop
}
In order for g++ to get it compiled you will need to add a default constructor:
aggregate_wrapper() = default;
please see it in action at: http://coliru.stacked-crooked.com/a/df1ac057960bebc7
I have the feeling that clang under the hood added it, but I am not 100% sure ...
GCC is wrong. Its diagnostic, in part, says:
main.cpp:34:25: note: '<...>' is not usable as a constexpr function because:
main.cpp:34:25: error: enclosing class of constexpr non-static member function '<...>' is not a literal type
... but there is no such rule. See [dcl.constexpr]/3 for the list of constraints that apply here.
You can work around the bogus GCC diagnostic by adding a dummy constexpr constructor (it's fine for that constructor to be private and/or deleted if you don't want any of your real constructors to be constexpr) or by making size be static.