I've recently encountered code that looks like this
template <typename T>
void Foo()
{
T::Bar();
}
I'm confused, how does that compile? There's no constraint on T like in C# generics.
I realize templates are not like generics in that the former are basically glorified macros, so is the case simply that each usage of Foo is compiled against the T provided in that instance, and given that it has a Bar() function it works? Kind of like duck typing?
Is this how it worked since c++03 or is this something new in c++11?
This template function only impose that when substituing the type T, the expression T::Bar(); is valid, as long as it is valid, it will compile (there is no C#-like constraints in C++) :
Here are two examples using your template:
#include <iostream>
#include <functional>
struct X
{
static void Bar() { std::cout << "Bar X\n!"; }
};
struct Y
{
static std::function<void(void)> Bar;
};
std::function<void(void)> Y::Bar = []() { std::cout << "Bar Y!"; };
template <typename T>
void Foo()
{
T::Bar();
}
int main()
{
Foo<X>();
Foo<Y>();
return 0;
}
This is how templates work and have worked always, nothing new here in C++11. It compiles if T::Bar() is valid for a given type, so it is duck typing as you said. Most of the C++ standard library works based on this principle - e.g. an iterator needs the operator* to work, and if you have your own iterators they will work with standard algorithms provided you implement this operator (and other operations required based on the iterator category). You do not need to specify your iterator in any other way - just provide the required operations.
Templates are only compiled when you instantiate them, i.e. by doing
Foo<int>();
In that case the actual code is generated by substituting T for the concrete type that you passed in (which will of course lead to a compile error here since int has no static member function Bar).
This is by design and has always been around.
Related
I have to store arguments (parameter pack), and pass the arguments to another function.
As a result, I cannot use lambda. And a good choice is std::bind.
But for this code
struct A{};
void test(A &&){}
int main()
{
A a;
test(move(a)); //work
bind(test,a)(); //compile fail; copy a to std::bind, pass a to test
}
According to standard, all variables stored in std::bind will be pass as lvalue to function. (The C++ standard doesn't say that, by I think that is what it means.)
And that means I cannot use a function (has rvalue reference in parameter) with std::bind.
One solution is to change test(A &&) to test(A &), but this only works for your project (and make it strange while you not only need to call test by std::thread but also need to call test by plain sequential call).
So, is there any ways to solve this problem?
You can create wrapper which will be convertible to the rvalue reference (like reference_wrapper/l-value references) and use it with bind:
It cal look like that:
#include <iostream>
#include <functional>
struct A{};
void test(A &&){ std::cout << "Works!\n"; }
template <typename T>
struct rvalue_holder
{
T value;
explicit rvalue_holder(T&& arg): value(arg) {}
operator T&&()
{
return std::move(value);
}
};
template <typename T>
rvalue_holder<T> rval(T && val)
{
return rvalue_holder<T>(std::move(val));
}
int main()
{
A a;
test(std::move(a)); //work
auto foo = std::bind(test, rval(std::move(a))); //works
foo();
}
http://coliru.stacked-crooked.com/a/56220bc89a32c860
Note: both rvalue_holder and especially rval need further work to ensure efficiency, robustness and desired behavior in all cases.
It follows a minimal example of the bind function in use.
It compiles and it is pretty trivial an example indeed.
#include <functional>
void fn(int i) { }
int main() {
int x = 0;
auto f = std::bind(fn, x);
}
I would be interested in doing the same with a templated function.
It follows the example above, even though slightly modified. This one doesn't compile, but it explains exactly which is the intended behavior.
#include <functional>
template<typename T>
void fn(T t) { }
int main() {
int x = 0;
auto f = std::bind(fn, x);
}
Quite simple a question: is it possible to use bind utility with a templated function?
I think the obvious solution is the code below.
#include <functional>
template<typename T>
void fn(T t) { }
int main() {
int x = 0;
auto f = std::bind(fn<int>, x);
}
If you don't want to be specific about the instantiation, maybe you can add one more template level. I'm making some tests.
EDIT: I spent a few hours thinking by myself, googling around and reading my printed TC++PL4Ed, as well as reading the implementation of GNU's libstdc++ source code, and I didn't figure nor did I find out how to do what you asked.
It turns out that when you made fn the name of a template, it could no longer be used as the name of an object. Since std::bind deduces its return type from (the types of) its arguments, the use of just fn became invalid. To have a callable object that qualifies as first argument to std::bind, you must now instantiate the template fn.
I am new to template programming. I have a question like this
A.process(B)
where A is a template parameter.
Is it fine for me to set B as a template parameter as well? By that I would be able to let different type A objects to process different type of objects B. B normally would not be used polymorphically in run time.
Thanks.
If I understand your requirement, then yes - you can do something like:
template <typename A, typename B>
void fn(A& a, B& b)
{
...other code...
a.process(b);
...other code...
}
Well, since we're all speculating on the meaning of the question, I'll offer what I think is in mind here. In the same way that one can create a template like -
template<typename T, std::size_t size = 50> struct fixed_array {
private:
T a[size];
};
...with "size" being an instance of an existing type, and not the name of a type, I think the questioner wants to know if one can do something like the following -
struct A_type {
... // whatever constitutes this class plus overloaded methods like ...
void process(int B) {
std::cout << "int overload: " << B << std::endl;
}
void process(const char* B) {
std::cout << "string overload: " << B << std::endl;
}
} A; // an actual instance of A_type
template<A_type A, int B> void foo() {
A.process(B); // will call the int overload
}
main() {
foo<A, 3>(); // produces the output "int overload: 3"
}
The answer is "no". At least, not as formulated above. There are restrictions on non-type template parameters that are well-summarized here: template parameters. The type of such a parameter has to conform to LiteralType, which includes references. So by tweaking the function definition as follows -
template<A_type& A, int B> void foo() {
A.process(B); // will call the int overload
}
Now we're good-to-go, and it satisfies the questioner's requirement to produce a template (class or function) in which A and B, both of which are clearly instances and not types, are both parameterized at compile time, such that A.process(B) can be understood and compiled. By C++20, there are a set of rules that allow the original formulation of foo if A_type obeys a number of conventions, but that's all covered in the above link. NOTE: while LiteralType entities can include references, the object of those references must be statically defined, either in the global declaration area or declared with the keyword static. The compiler must know the value at compile time, and it must be impossible to change at run-time. So for example the following -
template<A_type& A, const char* B> void bar() {
A.process(B);
}
this main definition will not compile -
main() {
bar<A, "hello">();
}
but the following will -
const char* h_string = "hello";
template<A_type& A, const char*& B> void bar() { // note the switch to reference
A.process(B);
}
main() {
bar<A, h_string>(); // will produce output "string overload: hello"
}
as will -
main() {
static const char* h_string = "hello";
bar<A, h_string>();
}
For reasons I can't quite work out, even using double in stead of int didn't work in the version of clang I tried this on, so it may not be as flexible a trick as the questioner would like. That being said, there are without doubt many other approaches to solving the questioner's higher level problem.
While experimenting a bit with C++ templates I managed to produce this simple code, for which the output is different, than I expected according to my understanding of C++ rules.
void bar(double d)
{
std::cout << "bar(double) function called" << std::endl;
}
template <typename T> void foo(T t)
{
bar(3);
}
void bar(int i)
{
std::cout << "bar(int) function called" << std::endl;
}
int main()
{
foo(3);
return 0;
}
When I compile this code in VC++2008 Express, function bar(int) gets called. That would be the behaviour, I would expect if bar(3);in the template body was dependent on the template parameter. But it's not. The rule I found here says "The C++ standard prescribes that all names that are not dependent on template parameters are bound to their present definitions when parsing a template function or class". Am I wrong, that "present definition" of bar when parsing the template function foo is the definition of
void bar(double d);? Why it's not the case if I am wrong. There are no forward declarations of bar in this compilation unit.
It is indeed a bug in the compiler. The problem was known to exist in VS2005 and before (I use a Blogspot blog as a notebook for cases like this, see 1.3 here). Apparently it is present in VS2008 as well.
You can test it with the following simple code
int bar(double d) { return 0; }
template <typename T> void foo(T t) {
int i = bar(3);
}
void bar(int i);
int main() {
foo(3);
}
This code is well-formed (you can compile it with Comeau Online compiler), but I bet that VS will choke on it because VS implements the two-phase lookup incorrectly in this case.
AndreyT is correct. In fact, your code is virtually identical to an example from the standard (ยง14.6.3/1):
void g(double);
void h();
template<class T> class Z {
public:
void f() {
g(1); //calls g(double)
h++; //ill-formed: cannot increment function;
// this could be diagnosed either here or
// at the point of instantiation
}
};
void g(int); // not in scope at the point of the template
// definition, not considered for the call g(1)
What is compile-time polymorphism and why does it only apply to functions?
Way back when, "compile time polymorphism" meant function overloading. It applies only to functions because they're all you can overload.
In current C++, templates change that. Neil Butterworth has already given one example. Another uses template specialization. For example:
#include <iostream>
#include <string>
template <class T>
struct my_template {
T foo;
my_template() : foo(T()) {}
};
template <>
struct my_template<int> {
enum { foo = 42 };
};
int main() {
my_template<int> x;
my_template<long> y;
my_template<std::string> z;
std::cout << x.foo << "\n";
std::cout << y.foo << "\n";
std::cout << "\"" << z.foo << "\"";
return 0;
}
This should yield 42, 0, and "" (an empty string) -- we're getting a struct that acts differently for each type.
Here we have "compile time polymorphism" of classes instead of functions. I suppose if you wanted to argue the point, you could claim that this is at least partially the result of the constructor (a function) in at least one case, but the specialized version of my_template doesn't even have a constructor.
Edit: As to why this is polymorphism. I put "compile time polymorphism" in quotes for a reason -- it's somewhat different from normal polymorphism. Nonetheless, we're getting an effect similar to what we'd expect from overloading functions:
int value(int x) { return 0; }
long value(long x) { return 42; }
std::cout << value(1);
std::cout << value(1L);
Function overloading and specialization are giving similar effects. I agree that it's open to some question whether "polymorphism" applies to either, but I think it applies about equally well to one as the other.
With compile time polymorphism one usually means the fact that you can have a several functions with the same name and the compiler will choose at compile time which one to used depending on the arguments:
void foo(int x);
void foo(float y);
//Somewhere else
int x = 3;
foo(x); //Will call first function
float y = 2;
foo(y); //Will call second function
The function foo is said to be overloaded. Various types of template instantiation could also be called compile time polymorphism.
Compile time polymorphism is a term that refers to C++ template programming. For example, at compile time you determine the actual type of a std::vector by what it contains:
std::vector <int> vi;
std::vector <std::string> vs;
I'm not sure why you think it it is limited to functions.
The thing which only applies to functions is template parameter deduction. If I have a function template:
template <typename T>
void foo(T &t);
Then I can do int a = 0; foo(a);, and this will be equivalent to int a = 0; foo<int>(a);. The compiler works out that I mean foo<int>. At least, it works out that it should use foo<int> - if that's not what I meant then bad luck to me, and I could have written foo<unsigned int>(a); or whatever.
However, if I have a class template:
template <typename T>
struct Foo {
T &t;
Foo(T &t) : t(t) {}
T &getT() { return t; }
};
Then I can't do int a = 0; Foo(a).getT();. I have to specify Foo<int>(a). The compiler isn't allowed to work out that I mean Foo<int>.
So you might say that class templates are "less polymorphic" than function templates. Polymorphism usually means that you don't have to write code to make the type of your object explicit. Function templates allow that (in this particular case), and class templates don't.
As for why this is the case - the standard says so, I don't know why. The usual suspects are (a) it's too difficult to implement, (b) it's not useful, in the opinion of the standard committee, or (c) it creates some contradiction or ambiguity somewhere else in the language.
But you can still do other kinds of polymorphism with classes:
template <typename T>
struct Foo {
T &t;
Foo(T &t): t(t) {}
void handleMany(int *ra, size_t s) {
for (size_t i = 0; i < s; ++i) {
t.handleOne(ra[i]);
}
}
};
This is usually also called compile-time polymorphism, because as far as the author of the template is concerned, t.handleOne could be anything, and what it is will be resolved when necessary, "later" in the compilation when Foo is instantiated.
Compile time polymorphism applies to functions and operator overloads.
Read this http://cpp-tutorial.cpp4u.com/OOP_polymorphism.html