Disambiguate recursive definition of template function - c++

I am building a statically typed Matrix where all operations with matrices are typechecked. However, I am having issues when I want to do something that modifies the Matrix based on given number.
For instance, adding one column is trivial:
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
However, adding N columns is way harder. Since is impossible to typecheck with a function that has a branch where the return type is not the expected (even if the branch condition guarantees it) I can only think about a recursive approach:
template<int A, int B, int Z>
Matrix<A,B+1> addZCols(Matrix<A,B> m1) {
return addOneCol(m1);
}
template<int A, int B, int Z>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<A,B,Z-1>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
However, this is overloading addZCols in the return type, what is not allowed and leads to an error saying that calling addZCalls is ambiguous and cannot chose one of the 2 candidates. And what I want is that the version wiht B+1 is only called as the base case, so to speak, when Z=1.
Any idea about how to make this work or a different approach?

If I understand your requirement correctly, you could simply write the function template like this:
template<int A, int B, int Z = 1>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
and then use it like this:
Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<1,1,3>(Matrix<1,1>{});
By default, the 3rd parameter is 1, and so this function template can be used as addOneCol.
As #Evg points out, template parameters have the nice property that default arguments can appear in any order, so we could have the Z argument in the first position:
template<int Z = 1, int A, int B>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
This allows you to make the call more conveniently, like this:
Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
Since only Z needs to be specified, as A, and B can be deduced from the Matrix argument.

There may be a more efficient approach, but with the recursion solution that you proposed, SFINAE can be used to disambiguate the two versions of the template function.
#include <type_traits>
template <int A, int B>
struct Matrix {
constexpr int rows() const { return A; }
constexpr int cols() const { return B; }
int data;
};
template<int Z, int A, int B, std::enable_if_t<Z == 0, int> = 0>
Matrix<A, B> addZCols(Matrix<A,B> m1) {
return m1;
}
template<int Z, int A, int B, std::enable_if_t<Z != 0, int> = 0>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<Z-1, A, B>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
int main() {
Matrix<2, 2> m1;
auto m2 = addZCols<3>(m1);
static_assert(m2.rows() == 2, "check rows");
static_assert(m2.cols() == 5, "check cols");
return 0;
}
I have also offset the recursion limit by one for clarity and re-ordered the template parameters of addZCols to make it nicer to call, but it works just the same with your original signature.

Related

How to implicitly cast all arguments of a template function to the highest resolution type?

In a project I'm working on I have a templated function similar to this where all of the arguments should be of type T
#include <iostream>
template<typename T> bool aWithinBOfC(T a, T b, T c)
{
return std::abs(a - c) < b;
}
the issue I'm having is it won't compile if all of the arguments are not of the same type but it seems reasonable that it should implicitly cast similar types to the one with the highest resolution before evaluation. Is there any way to get a call like this to be valid?
int main()
{
double a{1.2};
double b{1.4};
float c{0.1f};
std::cout << aWithinBOfC(a, b, c) << std::endl;
}
Something along these lines, perhaps:
template<typename T>
bool aWithinBOfCImpl(T a, T b, T c) {
/* actual implemenattion */
}
template <typename ... Args>
auto aWithinBOfC(Args... args) {
return aWithinBOfCImpl<std::common_type_t<Args...>>(args...);
}
Demo
You don’t need implicit conversions at the call site. The compiler will implicitly convert the types to the largest one in the expression in the return statement.
template <class T, class U, class V>
bool aWithinBOfC(T a, U b, V c) {
return std::abs(a - c) < b;
}

Three argument function template confusing example

#include <iostream>
// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
std::cout << "max<T>() \n";
return b < a ? a : b;
}
// maximum of three values of any type:
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c); // uses the template version even for ints
} //because the following declaration comes
// too late:
// maximum of two int values:
int max (int a, int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
int main()
{
::max(47,11,33); // OOPS: uses max<T>() instead of max(int,int)
}
In this example (from book noted below) I didnt understand why ::max(47,11,33) call expected to use max(int,int). So one is 2 argument another is 3 argument i think it uses 3 argument function definition as it should.
Am I missing something?
Note: David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor C++ Templates: The Complete Guide [2nd ed.] book
The issue that is being raised is that the non-template overload will not be called.
The max<T>(T a, T b, T c) knows about max<T>(T a, T b) but DOESN'T know that there's an integer overload because it's declared after it.
A solution being: specialize max<T>for T = int rather than define a int(int, int) function:
#include <iostream>
template<typename T>
T max (T a, T b)
{
std::cout << "max<T>() \n";
return b < a ? a : b;
}
template<>
int max (int a, int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c);
}
int main()
{
::max(47,11,33); // BINGO: uses specialized max<int>()
}
Output:
max(int,int)
max(int,int)
This is brittle though, if a non-template function come to use max<int> after max<T> has been defined and before max<int> has been specialized, as per [temp.expl.spec]/6 the program would be ill-formed, no diagnostic required.
If this is a risk you cannot take, there are tools available to you. SFINAE is one of them and could forbid the general max<T> to be called with T = int. This would lead to either a working program or a compilation error.
::max(47, 11, 33); is in fact ::max<int>(47, 11, 33);
which in turns will call ::max<int>(::max<int>(47, 11), 33); which might be surprising.
As intis a built-in (so no ADL), max(int, int) should be visible before max(T, T, T) is defined to permit to call that version in template:
With custom type, thanks to ADL, your max function could be declared after:
template <typename T>
T max (T a, T b)
{
std::cout << "max<T>()\n";
return b < a ? a : b;
}
// Should be declared **before** max(T, T, T)
int max(int a, int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c);
}
struct S {};
// Might be declared after max(T, T, T)
S max(S, S)
{
std::cout << "max(S, S)\n";
return {};
}
Now, both max(0, 1, 2) and max(s, s, s) would call internally the non template overload.
Demo

Specifying default parameter when calling C++ function

Suppose I have code like this:
void f(int a = 0, int b = 0, int c = 0)
{
//...Some Code...
}
As you can evidently see above with my code, the parameters a,b, and c have default parameter values of 0. Now take a look at my main function below:
int main()
{
//Here are 4 ways of calling the above function:
int a = 2;
int b = 3;
int c = -1;
f(a, b, c);
f(a, b);
f(a);
f();
//note the above parameters could be changed for the other variables
//as well.
}
Now I know that I can't just skip a parameter, and let it have the default value, because that value would evaluate as the parameter at that position. What I mean is, that I cannot, say call, f(a,c), because, c would be evaluated as b, which is what I don't want, especially if c is the wrong type. Is there a way for the calling function to specify in C++, to use whatever default parameter value there is for the function in any given position, without being limited to going backwards from the last parameter to none? Is there any reserved keyword to achieve this, or at least a work-around? An example I can give would be like:
f(a, def, c) //Where def would mean default.
There isn't a reserved word for this, and f(a,,c) is not valid either. You can omit a number of rightmost optional parameters, as you show, but not the middle one like that.
http://www.learncpp.com/cpp-tutorial/77-default-parameters/
Quoting directly from the link above:
Multiple default parameters
A function can have multiple default parameters:
void printValues(int x=10, int y=20, int z=30)
{
std::cout << "Values: " << x << " " << y << " " << z << '\n';
}
Given the following function calls:
printValues(1, 2, 3);
printValues(1, 2);
printValues(1);
printValues();
The following output is produced:
Values: 1 2 3
Values: 1 2 30
Values: 1 20 30
Values: 10 20 30
Note that it is impossible to supply a user-defined value for z
without also supplying a value for x and y. This is because C++ does
not support a function call syntax such as printValues(,,3). This has
two major consequences:
1) All default parameters must be the rightmost parameters. The
following is not allowed:
void printValue(int x=10, int y); // not allowed
2) If more than one default parameter exists, the leftmost default
parameter should be the one most likely to be explicitly set by the
user.
As workaround, you may (ab)use boost::optional (until std::optional from c++17):
void f(boost::optional<int> oa = boost::none,
boost::optional<int> ob = boost::none,
boost::optional<int> oc = boost::none)
{
int a = oa.value_or(0); // Real default value go here
int b = ob.value_or(0); // Real default value go here
int c = oc.value_or(0); // Real default value go here
//...Some Code...
}
and then call it
f(a, boost::none, c);
Not exactly what you asked for, but you can use std::bind() to fix a value for a parameter.
Something like
#include <functional>
void f(int a = 0, int b = 0, int c = 0)
{
//...Some Code...
}
int main()
{
// Here are 4 ways of calling the above function:
int a = 2;
int b = 3;
int c = -1;
f(a, b, c);
f(a, b);
f(a);
f();
// note the above parameters could be changed
// for the other variables as well.
using namespace std::placeholders; // for _1, _2
auto f1 = std::bind(f, _1, 0, _2);
f1(a, c); // call f(a, 0, c);
return 0;
}
With std::bind() you can fix values different from default parameters' values or values for parameters without default values.
Take into account that std::bind() is available only from C++11.
You already have an accepted answer, but here's another workaround (that - I believe - has advantages over the other proposed workarounds):
You can strong-type the arguments:
struct A { int value = 0; };
struct B { int value = 2; };
struct C { int value = 4; };
void f(A a = {}, B b = {}, C c = {}) {}
void f(A a, C c) {}
int main()
{
auto a = 0;
auto b = -5;
auto c = 1;
f(a, b, c);
f(a, C{2});
f({}, {}, 3);
}
Advantages:
it's simple and easy to maintain (one line per argument).
provides a natural point for constricting the API further (for example, "throw if B's value is negative").
it doesn't get in the way (works with default construction, works with intellisense/auto-complete/whatever as good as any other class)
it is self-documenting.
it's as fast as the native version.
Disadvantages:
increases name pollution (better put all this in a namespace).
while simple, it is still more code to maintain (than just defining the function directly).
it may raise a few eyebrows (consider adding a comment on why strong-typing is needed)
If all parameters of the function were of distinct types, you could find out which parameters were passed and which were not and choose the default value for the latter.
In order to achieve the distinct type requirement, you can wrap your parameters and pass it to a variadic function template.
Then even the order of the argument does not matter anymore:
#include <tuple>
#include <iostream>
#include <type_traits>
// -----
// from http://stackoverflow.com/a/25958302/678093
template <typename T, typename Tuple>
struct has_type;
template <typename T>
struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
template <typename T, typename Tuple>
using tuple_contains_type = typename has_type<T, Tuple>::type;
//------
template <typename Tag, typename T, T def>
struct Value{
Value() : v(def){}
Value(T v) : v(v){}
T v;
};
using A = Value<struct A_, int, 1>;
using B = Value<struct B_, int, 2>;
using C = Value<struct C_, int, 3>;
template <typename T, typename Tuple>
std::enable_if_t<tuple_contains_type<T, Tuple>::value, T> getValueOrDefaultImpl(Tuple t)
{
return std::get<T>(t);
}
template <typename T, typename Tuple>
std::enable_if_t<!tuple_contains_type<T, Tuple>::value, T> getValueOrDefaultImpl(Tuple)
{
return T{};
}
template <typename InputTuple, typename... Params>
auto getValueOrDefault(std::tuple<Params...>, InputTuple t)
{
return std::make_tuple(getValueOrDefaultImpl<Params>(t)...);
}
template <typename... Params, typename ArgTuple>
auto getParams(ArgTuple argTuple)
{
using ParamTuple = std::tuple<Params...>;
ParamTuple allValues = getValueOrDefault(ParamTuple{}, argTuple);
return allValues;
}
template <typename... Args>
void f(Args ... args)
{
auto allParams = getParams<A,B,C>(std::make_tuple(args...));
std::cout << "a = " << std::get<A>(allParams).v << " b = " << std::get<B>(allParams).v << " c = " << std::get<C>(allParams).v << std::endl;
}
int main()
{
A a{10};
B b{100};
C c{1000};
f(a, b, c);
f(b, c, a);
f(a, b);
f(a);
f();
}
output
a = 10 b = 100 c = 1000
a = 10 b = 100 c = 1000
a = 10 b = 100 c = 3
a = 10 b = 2 c = 3
a = 1 b = 2 c = 3
live example
I will just use static functions to define default values that can change:
class defValsExample
{
public:
defValsExample() {
}
static int f1def_a() { return 1; }
static int f1def_b() { return 2; }
int f1(int a = f1def_a(), int b = f1def_b()) {
return a+b;
}
};
int main()
{
defValsExample t;
int c = t.f1(t.f1def_a(),4);
}

How can I distinguish overloads of templates with non-type parameters?

Here are two template functions, that differ only in their template parameters. The rest of the parameters are exactly the same.
template<int module>
void template_const(int &a,int & b){
a = a & module;
b = b % module;
}
template<bool x>
void template_const(int &a,int & b){
int w;
if (x){
w = 123;
}
else w = 512;
a = a & w;
b = b % w;
}
When I try to call them like this
template_const<true>(a,b)
or
template_const<123>(a,b)
the compiler tells me that the call is ambiguous. How can I call these two functions?
As #jogojapan pointed out, the problem is that the compiler cannot order these two functions, i.e. there is not one that is more specialized than the other. As explained in §14.5.6.2, when a call to an overloaded function template is ambiguous, the compiler uses a partial ordering between the various overloads to select the most specialized one.
To order the overloads, the compiler transforms each one of them and performs template argument deduction to see if one is more specialized than another one (there is a short explanation at the end of this answer). In your case, the two overloads are equivalent (or not comparable): template<int> void template_const(int &,int &) is not more specialized than template<bool> void template_const(int &, int &), and vice-versa.
Therefore, the compiler cannot select one over the other, hence generating an ambiguous call error.
If you are ok with explicitely specifying the type of the parameter you want to pass, you can use partial template specialization as follow:
template<typename T, T param>
struct template_const_impl;
template <int module>
struct template_const_impl<int, module>
{
static void apply(int &a, int &b)
{
a = a & module;
b = b % module;
}
};
template<bool x>
struct template_const_impl<bool, x>
{
static void apply(int &a, int &b)
{
const int w = x ? 123 : 512;
a = a & w;
b = b % w;
}
};
template <typename T, T param>
void template_const(int &a, int &b)
{
return template_const_impl<T, param>::apply(a, b);
}
int main()
{
int i = 512, j = 256;
template_const<int, 123>(i, j);
template_const<bool, true>(i, j);
}
This is not ideal, but it don't think there is a cleaner solution unless you can use C++11 and are willing to rely on some macros, in which case you can simplify the calling code a bit (idea taken from #Nawaz in this answer):
#define TEMPLATE_CONST(x) template_const<decltype(x), x>
int main()
{
int i = 512, j = 256;
TEMPLATE_CONST(123)(i, j);
TEMPLATE_CONST(true)(i, j);
}
I do not think it is going to work like this. You have overloads with same parameter types. Probably you will have to give them different names in the end and call them as you tried.

Determine type of argument

Is it somehow possible to reflect the type of the argument of a function at compile time?
So that
int b = add(3, 6)
Would result in a template instantiation in the form of
int add(int a, int b) { return a + b }
out of some however declared function template
A add(A a, B b) { return a + b }
I don't know if that is possible with templates they do not really seem to be made for heavy meta-programming.
template<typename T>
T add(T a, T b) { return a + b; }
Then you can call this with any built-in type (int, short, double, float, etc), and it will instantiate the function add at compile time, according to the type you use.
Note that if you split this into header/source, you will have trouble:
add.h:
template<typename T>
T add(T a, T b);
add.cpp:
template<typename T>
T add(T a, T b) { return a + b; }
main.cpp:
#include "add.h"
int a = 3;
int b = 5;
int i = add(a, b);
When you try to compile this, it will fail at link time. Here's why.
Compiling add.obj does not instantiate the add template method -- because it's never called in add.cpp. Compiling main.obj instantiates the function declaration -- but not the function body. So at link time, it will fail to find the definition of the add method.
Simplest fix is to just put the entire template function in the header:
add.h:
template<typename T>
T add(T a, T b) { return a + b; }
and then you don't even need the add.cpp file at all.
Doesn't this do what you're asking?
template <typename A, typename B>
A add(A a, B b) { return a + b; }
This is hardly "heavy meta-programming".
This is exactly the sort of thing templates do.
template <typename T>
inline T add(T a, T b) { return a + b; }
Allowing two different types gets a little bit trickier but is also possible.
If you plan on using anything other than simple types you want (in a header file):
template <typename A>
inline A add(const A& a, const A& b) { return a + b; }
Note the 'inline'.
As noted by others, the issue with mixed types is how to determine the return type from the argument types. Suppose we stick to simple types and have:
template
inline A add(A a, B b) { return a + b; }
Then this fails (likely with only a warning):
double d = add(1, 1.5); // Sets d to 2.0
So you have to do some work. For example:
template<class A, class B>
struct Promote
{
};
template<class A>
struct Promote<A,A>
{
typedef A Type;
};
template<>
struct Promote<int, double>
{
typedef double Type;
};
template<>
struct Promote<double, int>
{
typedef double Type;
};
The add function becomes:
template<class A, class B>
inline typename Promote<A,B>::Type add(A a, B b)
{
return a + b;
}
What all this does for you is ensure that the return type is the one you specify for adding a given pair of types. This will work even for complex types.
Templates do all their magic at compile time, but that seems to be quite adequate for what you're asking:
template <class T>
T add(T a, T b) { return a + b; }
It does get a bit more complex when the two might not match, so (for example) you could add an int to a double and get a double result. The current standard doesn't really support that1; with C++0x you can look into auto and decltype for such tasks.
1Though Boost typeof will often do the job.