So I understand that templates can provide a way to do generic programming for example :
template <typename T>
T add(T x, T y){ return x + y}
Now I am wondering is there any type check templates provide? Or should I just define x and y as an integer to avoid errors.
If you define operator+ for the type T, then there would be no problem.
Definitely, there will be type checking, so you won't be able to do something like:
string c = add(3UL, 2.0E4); /* ERROR: the type of the result and the types of the arguments must match */
Also, as has been appointed, T must be a type with add operator + defined on it. As far as you obey these rules, you are free to do whatever you want with your generic function.
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b)
{
return a + b;
}
int main()
{
string c = add(3UL, 'A');
}
Will lead to:
$ make pru
g++ pru.cc -o pru
pru.cc: In function ‘int main()’:
pru.cc:13:28: error: no matching function for call to ‘add(long unsigned int, char)’
pru.cc:13:28: note: candidate is:
pru.cc:6:3: note: template<class T> T add(T, T)
make: *** [pru] Error 1
Related
My final goal is to compute the power of a quadratic ideal which is implemented as struct variables in C using GMP library.
I have been given a library(ANTL), which contains generic optimized exponentiations using C++ templates, namespaces and NTL. This library does exponentiation for NTL types ZZ_p etc. and basic types like long, float etc..
I have to use the ANTL library to achieve my final goal - computing the power of an ideal, a C struct variable. Since I have never worked with templates and namespaces before I wanted to implement the power of a basic mpz_t variable before to see how everything works.
Now, I have four header files exp.hpp, expbin.hpp, impl.hpp, com.hpp and a main file exp.cpp as follows -
COM.HPP
#ifndef GMPL_COM_H
#define GMPL_COM_H
#include <gmp.h>
namespace GMPL {
template < class T >
inline void assign(T C, const T A)
{
mpz_set(C, A);
}
template<class T>
void mul (T C, const T A, const T B)
{
mpz_mul(C, A, B);
}
template<class T>
void sqr (T C, const T A)
{
mpz_mul(C, A, A);
}
}
#endif // guard
EXP.HPP
#ifndef EXP_H
#define EXP_H
#include "com.hpp"
namespace GMPL
{
template < class T >
class exp
{
public:
exp() {};
virtual ~exp() {};
virtual void power (T C, const T A, const NTL::ZZ & n) = 0;
};
} // GMPL
#endif // EXP_H
EXPBIN.HPP
#ifndef EXPBIN_H
#define EXPBIN_H
#include "exp.hpp"
namespace GMPL
{
template < class T >
class expbin : public exp<T>
{
public:
expbin() {};
~expbin() {};
void power (T C, const T A, const NTL::ZZ & n);
};
} // GMPL
// Unspecialized template definitions.
#include "impl.hpp"
#endif // EXPBIN_H
IMPL.HPP
using namespace GMPL;
//
// compute A^n using standard left-to-right binary method
//
template < class T >
void expbin<T>::power (T C, const T A, const NTL::ZZ & n)
{
assign(C,A);
for (register long i = NumBits(n)-2 ; i >= 0 ; i--)
{
sqr(C, C);
if (bit(n, i) == 1)
mul(C, C, A);
}
}
EXP.CPP
#include <NTL/lzz_p.h>
#include <gmp.h>
namespace GMPL {}
using namespace GMPL;
#include "expbin.hpp"
NTL_CLIENT
int main ()
{
// NTL variables
ZZ n;
// GMP variables
mpz_t aa;
mpz_t bb;
mpz_init(aa);
mpz_init(bb);
// generate random exponent of size 512 bits
RandomLen (n, 512); // NTL function
// initialize exponentiation classes
expbin<mpz_t> obj;
// compute a^n with available methods
obj.power (bb,aa,n);
// check and output results
gmp_printf("%Zd", bb);
}
when I try to compile EXP.CPP using (as mentioned on Victor Shoup's NTL documentation online)
g++ -g -O2 -std=c++11 -pthread -march=native exp.cpp -o t -lntl -lgmp -lm
I get the following error messages-
$ g++ -g -O2 -std=c++11 -pthread -march=native exp.cpp -o t -lntl -lgmp -lm
In file included from exp.cpp:8:
In file included from ./expbin.hpp:46:
./impl.hpp:16:10: warning: 'register' storage class specifier is deprecated and
incompatible with C++1z [-Wdeprecated-register]
for (register long i = NumBits(n)-2 ; i >= 0 ; i--)
^~~~~~~~~
./impl.hpp:15:5: error: no matching function for call to 'assign'
assign(C,A);
^~~~~~
exp.cpp:28:9: note: in instantiation of member function
'GMPL::expbin<__mpz_struct [1]>::power' requested here
obj.power (bb,aa,n);
^
./com.hpp:16:17: note: candidate template ignored: deduced conflicting types for
parameter 'T' ('__mpz_struct *' vs. 'const __mpz_struct *')
inline void assign(T C, const T A)
^
In file included from exp.cpp:8:
In file included from ./expbin.hpp:46:
./impl.hpp:20:13: error: no matching function for call to 'mul'
mul(C, C, A);
^~~
./com.hpp:22:10: note: candidate template ignored: deduced conflicting types for
parameter 'T' ('__mpz_struct *' vs. 'const __mpz_struct *')
void mul (T C, const T A, const T B)
Assiduous googling about these errors shows that one has to have an empty constructor in the parent class but I already have it.
I know the compile statement is correct because other than that nothing else works when using NTL. At this point I ran out of ideas to fix this. Thanks in advance.
EDIT
This question has been resolved. I wish for this question to be closed or removed.
One solution would be to not use templates for your function wrappers. It seems like there would be only one template parameter that ever makes sense (i.e. T replaced by mpz_t), given that the template parameter has to be compatible with mpz_set. Templates seem like the wrong tool for the job. Just define your wrappers taking parameters of type mpz_t and const mpz_t:
inline void assign(mpz_t C, const mpz_t A)
{
mpz_set(C, A);
}
You did say you wanted to learn templates, but using them in an inappropriate context is not going to be that helpful. And you still have the templates for your classes to learn from.
That being said, I can interpret the compiler messages for you.
warning: 'register' storage class specifier is deprecated and
incompatible with C++1z [-Wdeprecated-register]
for (register long i = NumBits(n)-2 ; i >= 0 ; i--)
This is an easy one to fix. Get rid of "register" in that line. It is no longer a performance optimization.
error: no matching function for call to 'assign'
assign(C,A);
[...]
note: candidate template ignored: deduced conflicting types for
parameter 'T'
The compiler is having trouble figuring out what to use as the template parameter in this function call. There are two function arguments, each implying what the template parameter for assign should be. (This is distinct from the template parameter for expbin, even though both are named T.) It's a problem when the implications are in conflict. One way to make this work should be to specify what you want the parameter to be, as in
assign<T>(C, A);
This makes it explicit that the template parameter for assign (given between < and >) is supposed to be the template parameter for expbin (the meaning of T in this context).
Note: The templates you defined look like they might normally work without having to specify T like this. However, mpz_t is technically an array of one structure (not simply a structure), and arrays used as arguments can decay, which can lead to type confusion.
error: no matching function for call to 'mul'
mul(C, C, A);
note: candidate template ignored: deduced conflicting types for
parameter 'T'
Same (although in this case there are three function arguments, so three deduced candidates for T).
mul<T>(C, C, A);
I'm trying to implement Functor and various other category-theoretic concepts using C++ concepts, but am getting compile errors:
http://coliru.stacked-crooked.com/a/e8b6eb387229bddf
Here's my full code (I know that requiring fmap<int, int> does not verify fmap for any two types, and I plan to change it to fmap<int, std::string> or something to achieve a slightly stronger test -- or instead, possibly alter the Functor concept so that it takes in addition to F, two types T and U and verifies the existence of fmap<T, U>, but that's all after I figure out how to fix the error that I'm getting):
#include <functional>
#include <iostream>
#include <vector>
// empty Functor_Impl struct - specialize for each functor
template<template<class> class F> struct Functor_Impl {};
// std::vector Functor implementation
template<>
struct Functor_Impl<std::vector> {
template<class T, class U>
static std::vector<U> fmap(std::vector<T> x, std::function<U(T)> f) {
std::vector<U> out;
out.reserve(x.size());
for (int i = 0; i < x.size(); i++) {
out.push_back(f(x[i]));
}
return out;
}
};
// Functor concept requires Functor_Impl<F> to have fmap
template<template<class> class F>
concept bool Functor = requires(F<int> x) {
{Functor_Impl<F>::template fmap<int, int>(x)} -> F<int>;
};
// Test function using constraint.
template<template<class> class F, class T>
requires Functor<F>
F<T> mult_by_2(F<T> a) {
return Functor_Impl<F>::template fmap<T, T>(a, [](T x) {
return x * 2;
});
}
int main() {
std::vector<int> x = {1, 2, 3};
std::vector<int> x2 = mult_by_2(x);
for (int i = 0; i < x2.size(); i++) {
std::cout << x2[i] << std::endl;
}
}
And the compile error:
lol#foldingmachinebox:~/p/website-editor$ g++ foo.cpp -std=c++17 -fconcepts -o foo
foo.cpp: In function ‘int main()’:
foo.cpp:39:38: error: cannot call function ‘F<T> mult_by_2(F<T>) [with F = std::vector; T = int]’
std::vector<int> x2 = mult_by_2(x);
^
foo.cpp:31:6: note: constraints not satisfied
F<T> mult_by_2(F<T> a) {
^~~~~~~~~
foo.cpp:24:14: note: within ‘template<template<class> class F> concept const bool Functor<F> [with F = std::vector]’
concept bool Functor = requires(F<int> x) {
^~~~~~~
foo.cpp:24:14: note: with ‘std::vector<int> x’
foo.cpp:24:14: note: the required expression ‘Functor_Impl<F>::fmap<int, int>(x)’ would be ill-formed
I'm guessing that my syntax for the concept itself is wrong - that it's treating a variable as a function, or vice versa, since I'm not very familiar with the concept syntax, and in addition some of the example code on cppreference.com does not compile under GCC's implementation (e.g. concept EqualityComparable does not compile, it must be changed to concept bool EqualityComparable).
If I remove requires Functor<F> from the mult_by_2 function declaration, then the code compiles and runs.
The problem is exactly what the error message says: Functor_Impl<F>::template fmap<int, int>(x) is not a valid expression. Functor_Impl<std::vector>::fmap has two parameters, not one.
I was trying out a sample generic function in C++ , the code follows:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
template <typename T>
T max(T a, T b){
return (a>b)?a:b;
}
int main()
{
int a=2,b=4;
float af = 2.01,bf=2.012;
double ad = 2.11,bd=1.22;
cout<<max(a,b);
}
I am getting the error as
main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
cout<<max(a,b);
^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
T max(T a, T b){
^main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
cout<<max(a,b);
^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
T max(T a, T b){
^main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
cout<<max(a,b);
^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
T max(T a, T b){
^
What am I doing wrong here ?
What is meant by call of overloaded max(int&, int&) is ambiguous ?
Why am I getting its argument shown as & where as there was no such syntax defined by me above ?
The problem is that C++ already has a std::max definition.
Pick another name and everything should be fine.
In C++ the using namespace std approach is a bad idea as thousands of names will be injected. Just get the habit of typing std:: in front of standard names.
Remember also that saving time when writing is not really that important, what is important is saving time when reading (normally code is written just once but read and understood many times).
std:: in front of standard names actually speeds up reading and lets understanding on the spot that what is being used is part of the standard library (not everyone knows the whole standard library by heart).
Skypjack and 6502's answers are spot on so I won't go over that here.
It is also worth noting that the standard's version of max is not that clever. You can cause it not to compile with code like this:
int main()
{
int a = 0;
double b = 1;
auto c = std::max(a, b);
}
yields error message:
16 : error: no matching function for call to 'max(int&, double&)'
If we wanted to rewrite max, we might imagine that we were improving it by writing it this way:
#include <type_traits>
namespace notstd {
template <typename T1, class T2>
auto max_any(T1 a, T2 b) -> std::common_type_t<T1, T2>
{
return (a>b) ? a : b;
}
}
int main()
{
int a = 0;
double b = 1;
auto c = notstd::max_any(a, b);
}
But of course there would be some consequences.
Firstly, max_any is now forced to take copies and (possibly) perform conversions. For integers and doubles this is almost not worth mentioning.
But if T1 and T2 were two classes of object that had appropriate conversion operators, calling max_any on them could potentially be an expensive operation. It might also have material side-effects.
For this reason, std::max is defined in terms of arguments of type T&. It forces the caller to perform the conversion. It turns out that this is not a limitation of std::max. It is a safety feature.
The function does not inject any hidden side-effects into your code.
In order to maintain 'the path of least surprise' in its behaviour, the standard library sometimes requires that its users spell out the surprising behaviour that they want.
Example of surprising behaviour
This program will compile perfectly:
#include <cstdlib>
#include <iostream>
namespace notstd {
template <typename T1, class T2>
auto max_any(T1 a, T2 b)
{
return (b < a) ? a : b;
}
}
struct A {
A() = default;
};
struct B {
B() = default;
B (A const&) { std::exit(100); }
};
bool operator<(B const&, A const &) { return true; }
int main()
{
A a;
B b;
auto c = notstd::max_any(a, b);
std::cout << "Hello, World\n";
}
But it will never print "Hello, World".
Someone maintaining this code might be surprised to learn that.
There exists already a max function in the standard template library (namely std::max).
Using the using namespace directive, you are importing the names from the std:: namespace to the one in which you are using the declaration itself.
You can still use the following line to pick your implementation of max:
cout << ::max(a,b);
Otherwise, as someone already mentioned, you can choose a different name for your function or use directly the one fron the standard template library.
I am learning c++ template concepts. I do not understand the following.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
T fun(T& x)
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
int main ( int argc, char ** argv)
{
int a[100];
fun (a);
}
What i am trying?
1) T fun (T & x)
Here x is a reference, and hence will not decayed 'a' into pointer type,
but while compiling , i am getting the following error.
error: no matching function for call to ‘fun(int [100])’
When I try non-reference, it works fine. As I understand it the array is decayed into pointer type.
C-style arrays are very basic constructs which are not assignable, copyable or referenceable in the way built-ins or user defined types are. To achieve the equivalent of passing an array by reference, you need the following syntax:
// non-const version
template <typename T, size_t N>
void fun( T (&x)[N] ) { ... }
// const version
template <typename T, size_t N>
void fun( const T (&x)[N] ) { ... }
Note that here the size of the array is also a template parameter to allow the function to work will all array sizes, since T[M] and T[N] are not the same type for different M, N. Also note that the function returns void. There is no way of returning an array by value, since the array is not copyable, as already mentioned.
The problem is in the return type: you cannot return an array because arrays are non-copiable. And by the way, you are returning nothing!
Try instead:
template <typename T>
void fun(T& x) // <--- note the void
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
And it will work as expected.
NOTE: the original full error message (with gcc 4.8) is actually:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:17:10: error: no matching function for call to ‘fun(int [100])’
fun (a);
^
test.cpp:17:10: note: candidate is:
test.cpp:7:3: note: template<class T> T fun(T&)
T fun(T& x)
^
test.cpp:7:3: note: template argument deduction/substitution failed:
test.cpp: In substitution of ‘template<class T> T fun(T&) [with T = int [100]]’:
test.cpp:17:10: required from here
test.cpp:7:3: error: function returning an array
The most relevant line is the last one.
In this code, I want to pass the address of x.y as the template parameter typename Name::Type leValue.
#include <iostream>
using std::cout;
using std::endl;
struct X {
X() : y(123) {}
const int y;
};
template<typename Name, typename Name::Type leValue>
void print() { cout << *leValue << endl; }
struct Foo {
typedef int X::* Type;
};
int main() {
X x;
print<Foo, &x.y>(); // What is the right syntax here?
}
However, with gcc 4.7.2, I get the following errors:
source.cpp: In function 'int main()':
source.cpp:22:5: error: parse error in template argument list
source.cpp:22:22: error: no matching function for call to 'print()'
source.cpp:22:22: note: candidate is:
source.cpp:11:6: note: template void print()
source.cpp:11:6: note: template argument deduction/substitution failed:
source.cpp:22:22: error: template argument 2 is invalid
If I instead change the typedef to typedef int Type;, and the print call to print<Foo, 3>();, then it works. I tried several things by looking at the error messages, but could not get the syntax right. I have also searched here, and found some useful posts dealing with template classes, but none dealing with template functions. I tried using those answers but it did not help.
Could you please help me with this syntax, or explain to me what I should try doing next to fix this?
Is this close to what you're looking for?
#include <iostream>
using std::cout;
using std::endl;
struct X {
X() : y(123) {}
const int y;
};
template<typename Name, typename Type, Type Name::*Member>
void print(Type& obj) { cout << obj.*Member << endl; }
int main() {
X x;
print<X, const int, &X::y>(x);
}
The address of x.y is unknown in compile time. You can take a pointer to the member y as template argument, however, you have to pass the address of the object instance in run-time.
It works when you change it to an int because your allowed to pass const ints as template parameters. Templates will not let you pass values as arguments because they need to be resolved at compile time.