Variadic templates and sizeof...() confusion - c++

I have a recursive variadic templated method that is called from a non-recursive variadic templated method (probably not relevant but I'll mention it just in case):
template < class T, class UnaryPredicate, typename... UnaryPredicates >
static bool checkPredicate( const T obj,
const UnaryPredicate& p,
UnaryPredicates... predicates )
{
bool output = p( obj );
if ( output && sizeof...( UnaryPredicates ) ) {
output = checkPredicate( obj, predicates... ); // The problem line.
}
return output;
}
However when called with:
.. = checkPredicate< Sy_simObject*, VisiblePredicate< Sy_simObject* >( .. );
It gives me the following error:
error: no matching function for call to
'Sy_project::checkPredicate(Sy_simObject* const&)'
I understand that the error is telling me that UnaryPredicates is empty, and there is no overload for just T, and sure enough if I put one in it compiles fine. But I don't understand how it could have gotten that far with the sizeof...( UnaryPredicates ) check in the conditional? Surely if there were no more it would have evaluated as false and the recursion would have ended?
I can fix it by just adding the overload, by I really want to understand why it doesn't work now.

Because if(cond) { body } is a runtime if. The fact that the compiler can know before-hand at compile time that it doesn't need to branch at runtime can be used to optimize the generated code, but it must not influence whether it complains about certain parts of the code.
If the code of the body is invalid if cond is false, the compiler will complain. What you are looking for is a static if, which controls whether certain parts of your code is processed by the compiler or not. There are proposals for such a thing for the next C++ version, but current C++ does not have such a construct.

Related

How to implement a function that safely cast any larger type to a smaller type in C++ using templates?

I'm trying to write a function that checks if the variable being cast can fit in the destination type, and assert() if not. Right now this is what I came up with. I didn't test it yet. I would like to make the template figure out the type of the varible being passed automatically, with something like typeid, although I don't really know what typeid really is. Is that possible? Also, I don't know much about templates.
template<typename from_T, typename to_T>
static inline to_T safe_cast(from_T variable)
{
assert(variable >= std::numeric_limits<to_T>::min());
assert(variable <= std::numeric_limits<to_T>::max());
return static_cast<to_T>(variable);
}
Well, if that is actually some function that already does this that I don't know of I will be glad to hear.
C++ Core Guidelines already has a gsl::narrow
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
You can see the Microsoft implementation here
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
template <class T, class U>
constexpr T narrow(U u) noexcept(false)
{
constexpr const bool is_different_signedness =
(std::is_signed<T>::value != std::is_signed<U>::value);
const T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u || (is_different_signedness && ((t < T{}) != (u < U{}))))
{
throw narrowing_error{};
}
return t;
}
You can see the explanation of the implementation on this SO post (it's for an older version of the implementation, but nothing substantially changed, so the answer still applies).

std::is_base_of and error with if

I've got problem with templates:
I have got two constructors and method:
.cpp:
Cell::Cell(sf::Vector2i& uPos, sf::Vector2f& cellDimensions, std::string& stateName)
:unitPosition(uPos)
{
setBasicParameters<std::string>(stateName,cellDimensions,uPos);
}
Cell::Cell(sf::Vector2i & uPos, sf::Vector2f & cellDimensions, int stateNumber)
:unitPosition(uPos)
{
setBasicParameters<int>(stateNumber,cellDimensions,uPos);
}
.hpp::
//Basic parameters which are being used by constructors
template < typename T = typename std::enable_if< std::is_base_of<int, T>::value, T>::type || typename std::enable_if< std::is_base_of<std::string, T>::value, T>::type>
void setBasicParameters(T& object, sf::Vector2f& cellDimensions, sf::Vector2i& uPos);
template<typename T>
inline void Cell::setBasicParameters(T& object, sf::Vector2f& cellDimensions, sf::Vector2i& uPos)
{
shape.setSize(cellDimensions);
shape.setOutlineThickness(cellDimensions.x / 10.0f); //10%
shape.setOutlineColor(constants::cell::FILL_COLOR);
shape.setPosition(uPos.x*cellDimensions.x, uPos.y*cellDimensions.y);
if (!StateSystem::isStateExist(object))
{
Logger::Log(constants::error::stateSystem::STATE_DOES_NOT_EXIST, Logger::STREAM::BOTH, Logger::TYPE::ERROR);
state = StateSystem::getNumberOfState(constants::defaults::EMPTY);
}
else
{
if (std::is_base_of<std::string, T>::value)
state = StateSystem::getNumberOfState(object);
else state = object;
setColor(StateSystem::getColorOfState(state));
}
}
and problem is there:
if (std::is_base_of<std::string, T>::value)
state = StateSystem::getNumberOfState(object);
else state = object;
In this if, I check a type of T, and if it is std::string, I use method from StateSystem which changes name to number. In the other way, if T is int, I don't need to change it so I am immediately assign T to state(state is int). But my compiler checks the dwo options and gives me errors:
Severity Code Description Project File Line Suppression State
Error C2440 '=': cannot convert from 'std::string' to 'uint8_t'
Severity Code Description Project File Line Suppression State
Error C2664 'int8_t mv::StateSystem::getNumberOfState(std::string)': cannot convert argument 1 from 'int' to 'std::string'
Can I repair it without do two diffrent methods?
The problem is that the if statement here...
if (std::is_base_of<std::string, T>::value)
...is a run-time branch. Even though is_base_of can be evaluated at compile-time, the compiler is forced to compile both branches of the if statement, even if their correctness relies on the is_base_of condition.
Can I repair it without two different methods?
C++17 introduces if constexpr (...), which does the branching at compile-time. This still requires both branches to be parseable, but only instantiates the one that matches the predicate. Therefore the non-taken branch can be "invalid" and your program will work as expected.
if constexpr (std::is_base_of<std::string, T>::value)
state = StateSystem::getNumberOfState(object);
else state = object;
If you do not have access to C++14 and you really don't want to use two different functions, you can implement an equivalent construct to if constexpr(...). The implementation requires a significant amount of boilerplate. The final result will look like this:
static_if(std::is_base_of<std::string, T>{})
.then([&](auto){ state = StateSystem::getNumberOfState(object); })
.else_([&](auto){ state = object; })(_);
I gave a talk at CppCon 2016 and Meeting C++ 2016 called "Implementing static control flow in C++14" which explains how static_if works and how to implement it yourself.
If you decide that using two different functions is acceptable, here's how you can solve the issue:
if (!StateSystem::isStateExist(object))
{
// ...as before...
}
else
{
dispatch(state, std::is_base_of<std::string, T>{});
// ...as before...
}
Where dispatch is defined as:
void dispatch(State& state, Object& object, std::true_type)
{
state = StateSystem::getNumberOfState(object);
}
void dispatch(State& state, Object& object, std::false_type)
{
state = object;
}
std::is_base_of is a compile-time thing. You should use it with static_assert, for example. Type information at runtime in C++ is something complicated and you should use stuff like RTTI or dynamic_cast for it.
This answer gives answers about the difference.

In C++17 can an if statement with an initializer be used to unpack an optional?

I'm writing some code using std::optional's and am wondering if C++17's 'if statements with initializers' will be able to help unpack values?
std::optional<int> optionalInt = GetOptionalInt();
I'm making up the function Unpack here:
if( auto [value, has_value] = optionalInt.Unpack(); has_value )
{
// Use value here.
}
But, my question is. Will C++17 'if statement with initializer' help here? If so, how would it be coded?
Update, this is actually mainly an issue when using optional which is extremely easy to misuse because the optional and *optional both return bools and you don't get any compiler warning when somebody trys to access the value and forgets the *.
There is not, and cannot possibly be, such an Unpack() function.
But you could certainly do:
if (std::optional<int> o = GetOptionalInt(); o) {
// use *o here
}
though the extra o check is kind of redundant.
This is one of those places where it'd be nice if optional<T> modeled a container of at most one element, so that you could do:
for (int value : GetOptionalInt()) {
// possibly not entered
}
but we don't have that interface.
In order for this to work, there has to be a value for the unpacked value if it isn't there.
So
template<class T, class U>
std::pair< T, bool > unpack_value( std::optional<T> const& o, U&& u ) {
return { o.value_or(std::forward<U>(u)), (bool)o } )
}
would do what you wanted.
But as an optional already returns if it is engaged in a bool context you really should just:
if (auto i = get_optional())
then use *i within the body.
...
Now if optional stated that operator* returned a reference, and that return value was defined but accessing it was not defined when it was not engaged, then you could write an Unpack method or function that doesn't require a default value.
As far as I am aware this is not true. And as it doesn't really add anything, I don't see why it should be true.
Maybe this would work:
auto optValue = getOptional();
if (auto value = *optValue; optValue) { ...use value here... }

Correct usage of `for_each_arg` - too much forwarding?

I'm really happy to have discovered for_each_arg(...), which makes dealing with argument packs much easier.
template<class F, class...Ts>
F for_each_arg(F f, Ts&&...a) {
return (void)std::initializer_list<int>{(ref(f)((Ts&&)a),0)...}, f;
}
I'm, however, confused on its correct usage. There are many arguments that need to be perfectly forwarded, but am I performing any unnecessary forwarding?
Reading the code becomes harder with excessive fowarding.
struct UselessContainer
{
// Expects a perfectly-forwarded item to emplace
template<typename T> void add(T&&) { }
};
// Creates an `UselessContainer` already filled with `mArgs...`
auto makeUselessContainer(TArgs&&... mArgs)
{
using namespace std;
UselessContainer result;
for_each_arg
(
[&result, &mArgs...] // Am I capturing the `mArgs...` pack correctly here?
(auto&& mX) // Am I passing the arguments to the lambda correctly here?
{
// Is this `forward` necessary?
result.add(forward<decltype(mX)>(mX));
// Could it be replaced with
// `result.add(forward(mX));`
// ?
},
forward<TArgs>(mArgs)... // I assume this `forward` is necessary.
);
return result;
}
All my questions/doubts are expressed in the comments in the above code example.
Every forward in your code is indeed necessary to perfectly forward all arguments until the end. Names of rvalue references are lvalues, so unless you're forwarding everytime you pass arguments on, the value category information is lost.
Also it is impossible to call forward without an explicit template argument list as the template parameter is only used in one, non-deduced context. In fact, a function template called without an explicit argument list cannot do the job.
You can try a macro to somewhat shorten the code:
#define FORWARD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
It then becomes
for_each_arg
(
// Removed superfluous capture
[&result] (auto&& mX) {
result.add(FORWARD(mX));
},
FORWARD(mArgs)...
);
It's also possible to use a macro instead of for_each_arg in the first place:
#define FOR_EACH_ARG(...) (void)std::initializer_list<int>{((__VA_ARGS__),0)...}
FOR_EACH_ARG( result.add(forward<TArgs>(mArgs)) );
for_each_arg (
[&](auto&& mX){
result.add(std::forward<decltype(mX)>(mX));
},
std::forward<TArgs>(mArgs)...
);
Just capture & when making this kind of lambda. If you must list, only &result need be captured.
forward<?> is always used with a type parameter.
Note Eric's for_each_arg is imperfect, and mostly about doing it in 140 characters or less. ;) Its imperfections are mild, and harmless here.
Here is an alternative:
First, write this:
template<class...Fs>
void do_in_order(Fs&&...fs){
int _[]={0,
(((void)(std::forward<Fs>(fs)())),0)...
};
(void)_; // kills warnings
}
it takes zero arg lambdas, and runs them left to right.
Then replace the call to for_each_arg with:
do_in_order(
[&]{
result.add(std::forward<TArgs>(mArgs));
}...
);
the downside is that more compilers won't like the above.
Ordering of the expressions in the do_in_order is guaranteed by [dcl.init] and [dcl.init.list] sections in n4296 8.5.4/4 8.5.4/1 8.5/15 8.5/1. The initialization is a copy-list-initialization (8.5/15 and 8.5.4/1), is a "initializer-list of a braced-init-list" (8.5/1) and as such is sequenced left to right (8.5.4/4).

How to use the auto and decltype keywords to ease template argument deduction?

I am implementing the Merge sort algorithm. The problem is when I try to use a vector of automatically deduced types within the algorithm.
template <typename TIterator, typename TCompare>
void mergeSort(TIterator begin, TIterator end, TCompare criterium)
{
//...
auto help = *begin; // help is a value (not a reference)
QVector<decltype(help)> leftPart; // now decltype(help) is also a value
//... // and not a reference
}
This works.
But once I make the algorithm pass the TIterators by constant reference, I get an error which I never got in my whole life:
template <typename TIterator, typename TCompare>
void mergeSort(const TIterator& begin, const TIterator& end, TCompare criterium)
{
//...
auto help = *begin; // help is a value (not a reference)
QVector<decltype(help)> leftPart; // now decltype(help) is also a value
//...
}
results in:
In function 'void mergeSort(const TIterator&, const TIterator&, TCompare)':
internal compiler error: in type_unification_real, at cp/pt.c:14176
I am using g++ 4.6.3 on Ubuntu
What went wrong?
An internal compiler error occurs whenever the compiler fails, which means that you found a bug. This is the reason while early adoption of new standards is usually called the bleeding edge: sometimes, it makes you bleed ;)
There might be something wrong with your code, or there might not. It's not possible to tell from this output alone. What is certain is that the compiler does not support it so you might want to change it instead.
In particular, lookup std::iterator_traits<> to see all the things you can deduce from an iterator's type:
typename std::iterator_traits<TIterator>::value_type help = *begin;
// ::reference
// ::pointer
// ...
By circumventing the automatic deduction, you will probably be able to get past the compiler bug.
Note: if you wish to report the bug, which is certainly laudable, you will be asked to produce a preprocessed file reproducing the issue. This file should be as small as possible. It can be generated using -E on the gcc command line and generally ends up with the .ii extension.