4
\$\begingroup\$

I made a simple script to implement basic mathematics operations by using variadic functions. I would like to know if my implementation is correct.

The code only works for Visual C++ compiler Nov 2013 CTP (CTP_Nov2013).

#include <iostream>
#include <string>
#include <exception>
using namespace std;

template <typename T>
T add(T&& item = T())
{
    return forward<T>(item);
}

template <typename T, typename ... Types>
auto add(T&& first, Types&& ... rest)
    -> decltype(first + add(forward<Types>(rest)...))
{
    return forward<T>(first) + add(forward<Types>(rest)...);
}

template <typename T>
T sub(T&& i = T())
{
    return forward<T>(i);
}

template <typename T, typename ... Types>
auto sub(T&& first, Types&& ... rest)
-> decltype(forward<T>(first) - sub(forward<Types>(rest)...))
{
    return forward<T>(first) - sub(forward<Types>(rest)...);
}

template <typename T>
T multiple(T&& i = T())
{
    return forward<T>(i);
}

template <typename T, typename ... Types>
auto multiple(T&& first, Types&& ... rest)
-> decltype(forward<T>(first) * multiple(std::forward<Types>(rest)...))
{
    return forward<T>(first) * multiple(forward<Types>(rest)...);
}

template <typename T>
T divide(T&& item = T())
{
    return forward<T>(item);
}

template <typename T, typename ... Types>
auto divide(T&& first, Types&& ... rest)
    -> decltype(forward<T>(first) / divide(forward<Types>(rest)...))
{
    if (divide(forward<Types>(rest)...) == 0)
        throw "Opps divided by Zero";
    return forward<T>(first) / divide(forward<Types>(rest)...);
}

template<typename... Types>
void termnate(Types&&...)
{
    std::cout << '\n';
}

template<typename... Types>
void result(Types&&... t)
{
    termnate{ ([&]{ std::cout << forward<Types>(t) << ' '; }(), 1)... };
}

int main()
{
    result(     add(1, 2.5, 3, 4, 5), " = ", "1 + 2,5 + 3 + 4 + 5");

    result(sub(sub(sub(sub(1, 2.5), 3), 4), 5), " = ", "1 - 2.5 - 3 - 4 - 5"); // OK = -13.5

    result(multiple(1, 2.5, 3, 4, 5), " = ", "1 x 2.5 x 3 x 4 x 5");

    result(divide(divide(divide(divide(1, 2.5), 3), 4.5), 5), " = ", "1 / 2.5 / 3 / 4 / 5"); // OK = .005926


    cout << add("\nTest ", "template: ", string("PASS\n"));
}
\$\endgroup\$
11
  • 2
    \$\begingroup\$ Subtraction and division are not associative, so I am not sure how to define correctness of their variadic versions. Obviously, division by 0 returning 1 is wrong. \$\endgroup\$ – vnp Dec 10 '14 at 6:43
  • \$\begingroup\$ @vnp ... yes, i was testing static_assert() but it won't be, i dunno why \$\endgroup\$ – MORTAL Dec 10 '14 at 6:50
  • \$\begingroup\$ I'm fairly certain that you should be using forward when you pass on the && move references in the recursive calls. \$\endgroup\$ – glampert Dec 10 '14 at 13:31
  • 1
    \$\begingroup\$ Don't forget to explicitly pass the template type (e.g.: std::forward<T>(x)), it can't figure out the type by itself otherwise. \$\endgroup\$ – glampert Dec 10 '14 at 13:36
  • 1
    \$\begingroup\$ @glampert .. thanks that really deserve tobe an answer \$\endgroup\$ – MORTAL Dec 10 '14 at 13:53
2
\$\begingroup\$

When passing around move references, the recommended is to forward the parameters to ensure that the move reference is preserved:

template <typename T, typename ... Types>
auto add(T&& first, Types&& ... rest) 
    -> decltype(first + add(std::forward<Types>(rest)...))
{
    return first + add(std::forward<Types>(rest)...);
}

Note that you have to explicitly provide the template type to std::forward(). It would deduce the wrong type otherwise.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.