The following code is a snippet of a tuple-like class where it is possible to get a reference to a given type in the tuple, or if that type is not found, the provided default value will be returned instead.
If the default value is a lvalue a reference must be returned, if the default value is a rvalue then a rvalue must be returned.
The following code illustrates the problem I'm having:
struct Foo {
Foo(int d) : data(d) {}
template <typename T, typename TT>
const TT get_or_default(TT&& t) const {
return data;
}
template <typename T, typename TT>
TT get_or_default(TT&& t) {
return data;
}
int data;
};
int main(int argc, char* argv[]) {
int i = 6;
const Foo foo1(5);
Foo foo2(5);
// compile error
foo1.get_or_default<int>(i);
// works
foo1.get_or_default<int>(5);
foo2.get_or_default<int>(i) = 4;
foo2.get_or_default<char>('a');
return 0;
}
When compiling this I get the following error:
cxx.cxx:6:20: error: binding of reference to type 'int' to a value of type 'const int' drops qualifiers
return data;
^~~~
cxx.cxx:23:14: note: in instantiation of function template specialization 'Foo::get_or_default<int, int &>' requested here
foo1.get_or_default<int>(i);
^
1 error generated.
There is a special rule for template argument deduction when the function parameter is of type T&& where T is a template parameter. That rule is:
If the function argument is an lvalue of type U, then U& is used in place of U for type deduction in this case.
It's used to allow perfect forwarding. Basically, it means that T&& for a template parameter T is a "universal reference."
In your case, since i is indeed an lvalue, TT is deduced to int&. Applying a const to that is ignored (it would apply to the reference itself, not to the type referred to), so the fucntion instantiated from the template looks something like this:
int& get_or_default(int& t) const {
return data;
}
And since the function is const, data is considered const as well and so it cannot bind to a non-const reference.
Related
I'm trying to create a struct template with a variadic template type pack, that can deduct the sum of the size of all types passed in.
Below you find a simplified example, in the real-world context, the size computed is used to create further member objects.
template <typename... Types>
struct OverallSize
{
template <typename FirstType, typename... NextTypes>
static constexpr size_t sizesum() { return sizeof (FirstType) + sizesum<NextTypes...>(); }
template <typename LastType>
static constexpr size_t sizesum() { return sizeof (LastType); }
static constexpr size_t size = sizesum<Types...>();
};
// Should work e.g. like this
auto s = OverallSize<int, float, char>::size; // s will be 9 on x86-64
I'm used to this recursive parameter unpacking approach when it comes to argument lists and assumed this works as well with argument-less functions and explicit template specification. However I get the following error when compiling with clang
Call to 'sizesum' is ambiguous
...
Candidate function [with FirstType = unsigned long, NextTypes = <>]
Candidate function [with LastType = unsigned long]
So it seems as if the last recursion iteration doesn't work here – not sure why the compiler doesn't simply chose the most obvious choice: The one with only one template type – just as it would happen if there was an actual template argument passed to the function.
So, what do I have to do to make this compile and work as desired?
For C++14 you can use SFINAE:
template <
typename FirstType,
typename... NextTypes,
std::enable_if_t<sizeof...(NextTypes) >= 1>* = nullptr >
static constexpr size_t sizesum() {
return sizeof (FirstType) + sizesum<NextTypes...>();
}
this template will be considered only if parameters pack has size >= 1.
Demo
I'm having some trouble when using coeffRef() with a CWiseUnaryView function, but only when the function is declared as const
Reproducible example:
#include <Eigen/Core>
struct dummy_Op {
EIGEN_EMPTY_STRUCT_CTOR(dummy_Op)
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const double&
operator()(const double &v) const { return v; }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE double&
operator()(double &v) const { return v; }
};
void foo(Eigen::MatrixXd &out)
{
//Compiles
Eigen::CwiseUnaryView<dummy_Op, Eigen::MatrixXd> view(out);
view.coeffRef(0,0);
//Doesn't Compile
const Eigen::CwiseUnaryView<dummy_Op, Eigen::MatrixXd> const_view(out);
const_view.coeffRef(0,0);
}
Returns:
<source>: In function 'void foo(Eigen::MatrixXd&)':
<source>:21:28: error: passing 'const Eigen::CwiseUnaryView<dummy_Op,
Eigen::Matrix<double, -1, -1> >' as 'this' argument discards qualifiers
[-fpermissive]
const_view.coeffRef(0,0);
^
In file included from /opt/compiler-explorer/libs/eigen/v3.3.4/Eigen/Core:413,
from <source>:1:
/opt/compiler-explorer/libs/eigen/v3.3.4/Eigen/src/Core/DenseCoeffsBase.h:340:33: note:
in call to 'Eigen::DenseCoeffsBase<Derived, 1>::Scalar&
Eigen::DenseCoeffsBase<Derived, 1>::coeffRef(Eigen::Index, Eigen::Index)
[with Derived = Eigen::CwiseUnaryView<dummy_Op, Eigen::Matrix<double,
-1, -1> >; Eigen::DenseCoeffsBase<Derived, 1>::Scalar = double; Eigen::Index = long int]'
EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col)
^~~~~~~~
Compiler returned: 1
Compiler explorer: https://godbolt.org/z/kPHPuC
The side-effect of this, is that the multiplication of two (non-const) CWiseUnaryViews also fails, see example here: https://godbolt.org/z/JYQb3d
The bottom line is that you're calling a non-const method of a constant instance. The (first) coeffRef that is being called is the one (and only) in DenseCoeffsBase.h (DenseCoeffsBase<Derived, WriteAccessors>), which is not const qualified. The DenseCoeffsBase<Derived, ReadOnlyAccessors> class does not have a coeffRef method. You can get around this error (and get a warning) if you enable the -fpermissive compiler flag.
In the dense case, you probably want to use the operator()(Index, Index) method anyway, which does have a const qualified version. I just noticed the documentation explicitly says to use that method anyway, even for the non-const version. This is obviously not going to return a const reference, but at least in your example as a double, it shouldn't matter too much.
CwiseUnaryView is intended to be used for L-value like expression, e.g.,
MatrixXcd A;
A.real() = something; // `A.real()` is writable
If you want to apply an element-wise functor and use it as an R-value, you should use CwiseUnaryOp instead:
void foo(Eigen::MatrixXd &out)
{
Eigen::CwiseUnaryOp<dummy_Op, Eigen::MatrixXd> view1(out);
// shorter:
auto view2 = out.unaryExpr(dummy_Op());
Eigen::MatrixXd result = view1 * view2;
// or directly write: out.unaryExpr(dummy_Op()) * out.unaryExpr(dummy_Op());
}
Can anyone please explain how to use and access string in a union inside a structure with the help of unrestricted union?
#include <iostream>
#include <string>
using namespace std;
typedef struct {
int height;
int width;
} Page;
typedef struct {
int test;
union {
Page page;
int intVar;
string stringVar;
} VarUnion;
} VariableDataStruct;
int main()
{
VariableDataStruct structeg;
structeg.VarUnion.stringVar = "Hello";
return 0;
}
Currently getting following errors on compilation:
unionstring2.cc: In function ‘int main()’:
unionstring2.cc:22:24: error: use of deleted function ‘VariableDataStruct::VariableDataStruct()’
VariableDataStruct structeg;
^
unionstring2.cc:11:16: note: ‘VariableDataStruct::VariableDataStruct()’ is implicitly deleted because the default definition would be ill-formed:
typedef struct {
^
unionstring2.cc:11:16: error: use of deleted function ‘VariableDataStruct::::()’
unionstring2.cc:13:19: note: ‘VariableDataStruct::::()’ is implicitly deleted because the default definition would be ill-formed:
union {
^
unionstring2.cc:16:11: error: union member ‘VariableDataStruct::::stringVar’ with non-trivial ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char; _Traits = std::char_traits; _Alloc = std::allocator]’
string stringVar;
^
unionstring2.cc:11:16: error: use of deleted function ‘VariableDataStruct::::~()’
typedef struct {
^
unionstring2.cc:13:19: note: ‘VariableDataStruct::::~()’ is implicitly deleted because the default definition would be ill-formed:
union {
^
unionstring2.cc:16:11: error: union member ‘VariableDataStruct::::stringVar’ with non-trivial ‘std::basic_string<_CharT, _Traits, _Alloc>::~basic_string() [with _CharT = char; _Traits = std::char_traits; _Alloc = std::allocator]’
string stringVar;
^
unionstring2.cc:22:24: error: use of deleted function ‘VariableDataStruct::~VariableDataStruct()’
VariableDataStruct structeg;
^
unionstring2.cc:18:11: note: ‘VariableDataStruct::~VariableDataStruct()’ is implicitly deleted because the default definition would be ill-formed:
} VariableDataStruct;
^
unionstring2.cc:18:11: error: use of deleted function ‘VariableDataStruct::::~()’
The error you're getting is not about accessing union, it's about not being able to instantiate your struct:
error: use of deleted function ‘VariableDataStruct::VariableDataStruct()’
You need to provide a constructor for your struct that sensibly initializes the union.
Unions with members with non-trivial special member functions (constructor, assignment, destructors) (such as std::string) must define these special functions as well. Since this union does not provide the designation which member is currently in use, those special member functions cannot be defined.
Use std::variant<Page, int, std::string> instead.
I have the following construct:
template <class... Args>
class some_class
{
public:
some_class() = default;
some_class(Args...) = delete;
~some_class() = default;
};
template<>
class some_class<void>
{
public:
some_class() = default;
~some_class() = default;
};
The reason for this is that I just want to allow the users to create objects using the default constructor, so for example:
some_class<int,float> b;
should work but
some_class<int,float> c(1,3.4);
should give me a compilation error.
At some point in time I also needed to create templates based on void hence, the specialization for void:
some_class<void> a;
But by mistake I have typed:
some_class<> d;
And suddenly my code stopped compiling and it gave me the error:
some_class<Args>::some_class(Args ...) [with Args = {}]’ cannot be
overloaded
some_class(Args...) = delete;
So here comes the question: I feel that I am wrong that I assume that some_class<> should be deduced to the void specialization... I just don't know why. Can please someone explain why some_class<> (ie: empty argument list) is different from some_class<void>? (A few lines from the standard will do :) )
https://ideone.com/o6u0D6
void is a type like any other (an incomplete type, to be precise). This means it can be used as a template argument for type template parameters normally. Taking your class template, these are all perfectly valid, and distinct, instantiations:
some_class<void>
some_class<void, void>
some_class<void, void, void>
some_class<void, char, void>
In the first case, the parameter pack Args has one element: void. In the second case, it has two elements: void and void. And so on.
This is quite different from the case some_class<>, in which case the parameter pack has zero elements. You can easily demonstrate this using sizeof...:
template <class... Pack>
struct Sizer
{
static constexpr size_t size = sizeof...(Pack);
};
int main()
{
std::cout << Sizer<>::size << ' ' << Sizer<void>::size << ' ' << Sizer<void, void>::size << std::endl;
}
This will output:
0 1 2
[Live example]
I can't really think of a relevant part of the standard to quote. Perhaps this (C++11 [temp.variadic] 14.5.3/1):
A template parameter pack is a template parameter that accepts zero or more template arguments. [ Example:
template<class ... Types> struct Tuple { };
Tuple<> t0; // Types contains no arguments
Tuple<int> t1; // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error; // error: 0 is not a type
—end example ]
This looks like an issue in clang (I've already opened a bug here), but I'd like to be sure that I'm not doing a mistake.
Consider the following code:
#include <type_traits>
#include <cstddef>
template<std::size_t N, std::size_t M, std::enable_if_t<not (N>M)>* = nullptr> // (1)
struct S: public S<N+1, M> { };
template<std::size_t N>
struct S<N, N> { };
int main() {
S<0, 1> c{};
}
It fails to compile with the following error:
8 : error: non-type template argument specializes a template parameter with dependent type 'std::enable_if_t M)> *' (aka 'typename enable_if M), void>::type *')
struct S { };
The same code works as expected using the following line instead of (1):
template<std::size_t N, std::size_t M, typename = std::enable_if_t<not (N>M)>>
The SFINAE expression is almost the same. It is based on a specialization of std::enable_if_t and I would expect the same result (success or failure) for both of the examples.
Are my expectations wrong?
Note that GCC works fine in either cases.
I think this is a gcc bug actually, as a result of [temp.class.spec]:
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
In your example, the type of the 3rd template parameter is dependent on a parameter. When you swap it to typename = std::enable_if_t<...>, then this rule no longer applies.
Note: is there any reason to use SFINAE here anyway, as opposed to static_assert-ing?