Can i call foo(const T*&) in the following situation?
#include <iostream>
template <typename T>
void foo(const T*&)
{
std::cout << "::foo(const T*&) \n";
}
template <typename T>
void foo(const T&)
{
std::cout << "::foo(const T&) \n";
}
You are confused by the fact that const T*& means a reference to a pointer to const T, rather than a const-reference to a pointer to T.
To call that version of foo, use
int main()
{
const int *iptr = 0;
foo(i);
return 0;
}
Alternatively (and probably as intended), change the function signature to T *const &, i.e. a const-reference to a pointer to T.
No, you can't with that code, because there is an implicit conversion and you will end up calling the foo(const T&) version.
If you want to separate the two behaviours use explicit:
template <typename T>
void foo(const T*&)
{
std::cout << "::foo(const T*&) \n";
}
template <typename T>
void foo(explicit const T&)
{
std::cout << "::foo(const T&) \n";
}
int main()
{
int x;
int *y=&x;
foo(x);
foo(y);
return 0;
}
This way foo(x) will call foo(const T&), whereas foo(y) will call foo(const T*&)
Related
So I was trying to write a default function version when there are no template arguments passed in the following code:
struct A{ int x; };
struct B : public A { int y;};
struct C {
void set(const A& v) { v_ = v; }
template <typename T>
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
template <>
const A& get() { return v_;}
A v_;
};
int main() {
B b;
C c;
c.set(b);
(void)c.get<B>().y;
(void)c.get<A>().x;
//(void)c.get().x; << Error
}
But it doesn't work at the indicated Error line above with this error:
test.cpp:22:13: error: no matching member function for call to 'get'
(void)c.get().x;
~~^~~
test.cpp:9:14: note: candidate template ignored: couldn't infer template argument 'T'
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
^
1 error generated.
I do understand the issue that since no template argument was passed in the client call, it was unable to infer the typename but is there a way to provide a default implementation like the one in the above code when that happens? Essentially I want to avoid writing client code as (void)c.get<A>().x; and instead, adopt the default route implicitly.
As an alternative solution, you can specify A as default template argument for parameter T, e.g.
struct C {
void set(const A& v) { v_ = v; }
template <typename T = A>
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
template <>
const A& get() { return v_;}
A v_;
};
int main() {
B b;
C c;
c.set(b);
(void)c.get<B>().y; // call the primary template
(void)c.get<A>().x; // call the specification
(void)c.get().x; // call the specification
}
You can delete the template <> part.
struct C {
void set(const A& v) { v_ = v; }
template <typename T>
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
const A& get() { return v_;}
A v_;
};
The following code works:
template <typename T>
struct Foo
{
template <typename OStream>
static void default_print_function(OStream &, const T &);
template <typename OStream, typename PrintFunction>
void print(
OStream &,
const PrintFunction & = &Foo<T>::default_print_function<OStream>) const;
template <typename OStream>
void print(OStream &) const;
};
template <typename T>
template <typename OStream>
void Foo<T>::default_print_function(OStream & o, const T & value)
{
o << value;
}
template <typename T>
template <typename OStream, typename PrintFunction>
void Foo<T>::print(OStream & o, const PrintFunction & f)
const
{
T test_value = 123;
o << "TEST: ";
f(o, test_value);
}
template <typename T>
template <typename OStream>
void Foo<T>::print(OStream & o)
const
{
print(o, &default_print_function <OStream>);
}
#include <iostream>
int main()
{
Foo <int> foo;
foo.print(std::cerr, &Foo<int>::default_print_function<std::ostream>);
std::cerr << std::endl;
foo.print(std::cerr);
std::cerr << std::endl;
}
However, if I comment out the void print (OStream &) const overload:
template <typename T>
struct Foo
{
template <typename OStream>
static void default_print_function(OStream &, const T &);
template <typename OStream, typename PrintFunction>
void print(
OStream &,
const PrintFunction & = &Foo<T>::default_print_function<OStream>) const;
template <typename OStream>
void print(OStream &) const;
};
template <typename T>
template <typename OStream>
void Foo<T>::default_print_function(OStream & o, const T & value)
{
o << value;
}
template <typename T>
template <typename OStream, typename PrintFunction>
void Foo<T>::print(OStream & o, const PrintFunction & f)
const
{
T test_value = 123;
o << "TEST: ";
f(o, test_value);
}
/*template <typename T>
template <typename OStream>
void Foo<T>::print(OStream & o)
const
{
print(o, &default_print_function <OStream>);
}*/
#include <iostream>
int main()
{
Foo <int> foo;
foo.print(std::cerr, &Foo<int>::default_print_function<std::ostream>);
std::cerr << std::endl;
foo.print(std::cerr);
std::cerr << std::endl;
}
Then it won't compile:
test.cpp: In function ‘int main()’:
test.cpp:54:25: error: no matching function for call to ‘Foo<int>::print(std::ostream&)’
foo .print (std :: cerr);
^
test.cpp:8:7: note: candidate: template<class OStream, class PrintFunction> void Foo<T>::print(OStream&, const PrintFunction&) const [with OStream = OStream; PrintFunction = PrintFunction; T = int]
void print (
^~~~~
test.cpp:8:7: note: template argument deduction/substitution failed:
test.cpp:54:25: note: couldn't deduce template parameter ‘PrintFunction’
foo .print (std :: cerr);
The default value for the second argument for print is spelled in a way which seems to me to be exactly equivalent to the way it is spelled in the first invocation in the main function.
foo .print (std :: cerr, & Foo <int> :: default_print_function <std :: ostream>);
So why can the template argument be deduced in this invocation, but not be deduced in the default argument
const PrintFunction & = & Foo <T> :: default_print_function <OStream>
?
This is a non-deduced context:
cppreference
Non-deduced contexts:
...
4) A template parameter used in the parameter type of a function
parameter that has a default argument that is being used in the call
for which argument deduction is being done
EDIT (why it is a non-deduced context)
Because non-deduced context has a benefit: it allows the type to be used if it could be obtained from elsewhere.
Consider this example:
template<class T>
void foo(T, T = 1.0) {};
int main() {
foo(2);
}
This is valid code. But if it were not a non-deduced context, the deduction would conflict. It's somewhat reasonable to assume the programmer want to have a conversion instead of a failure.
On the other hand, the type is essentially given elsewhere (default argument that is given at declaration). For example, your code will be fine if you decltype to the template parameter:
template <typename OStream, typename PrintFunction = decltype(&Foo<T>::default_print_function<OStream>)>
All in all, we lose nothing to make it a non-deduced context. Moreover, we make the conversion of default argument type possible when the type is supplied elsewhere.
codereview would not allow hypothetical code, so I am posting here instead. Given this code:
#include <string>
struct foo {
std::string a, b;
foo (const std::string& a, const std::string& b) : a(a), b(b) { }
};
template <typename T> void bar (const T&) { }
template <typename T> void bar (T&&) { }
void execute (const foo& f) {
// etc...
bar(f.a);
// etc...
bar(f.b);
// etc...
bar(f);
// etc...
}
void execute (foo&& f) {
// etc...
bar(std::move(f.a));
// etc...
bar(std::move(f.b));
// etc...
bar(std::move(f));
// etc...
}
int main() {}
I want to write execute_helper to handle both execute overloads, since they are identical except for the std::move calls. Here is what I have, and I want to know if I did it correctly. I'm unsure about using T& and T in my check_move overloads, and whether passing T by value worsens the time complexity or not.
#include <string>
#include <iostream>
struct foo {
std::string a, b;
foo (const std::string& a, const std::string& b) : a(a), b(b) { }
};
template <typename T> void bar (const T&) { }
template <typename T> void bar (T&&) { }
template <typename T>
T check_move (const foo&, T& t) { std::cout << "std::move not called.\n"; return t; }
template <typename T>
T&& check_move (foo&&, T t) { std::cout << "std::move called.\n"; return std::move(t); }
template <typename F>
void execute_helper (F&& f) {
// etc...
bar(check_move(std::forward<F>(f), f.a));
// etc...
bar(check_move(std::forward<F>(f), f.b));
// etc...
bar(check_move(std::forward<F>(f), std::forward<F>(f)));
// etc...
}
void execute (const foo& f) {
execute_helper(f);
}
void execute (foo&& f) {
execute_helper(std::forward<foo>(f));
}
// Test
foo make_foo() {
return foo("hello", "bye");
}
int main() {
foo f("hello", "bye");
execute(f);
execute(make_foo());
}
Output:
std::move not called.
std::move not called.
std::move not called.
std::move called.
std::move called.
std::move called.
I have this program with 2 template functions :
#include <iostream>
template <class T> void assign(T& t1,T& t2){
std::cout << "First method";
t1=t2;
}
template <class T> void assign(T& t1,const T& t2) {
std::cout << "Second method";
t1=t2;
}
class A
{
public:
A(int a):_a(a){};
private:
int _a;
friend A operator+(const A& l, const A& r);
};
A operator+(const A& l, const A& r) {
return A(l._a+r._a);
}
int main ()
{
A a=1;
const A b=2;
assign(a,a+b);
}
i cant understand why does the assign(a,a+b) call the second template function
, in the operator+ we are createing a new A object and call the ctor with an int parameter.
it is creating a+b as const object ?
it is creating a+b as const object ?
No, it is creating a temporary. Temporaries are binded to rvalue references. You can verify that with a 'third' function (a universal reference, in this case)
template <class T>
void assign(T& t1, T&& t2) {
std::cout << "Third method";
t1=t2;
}
As you don't have one, the compiler will pick the const reference overload. Why ?
Suppose you have
void add(int & x)
{
++x;
}
unsigned y = 0;
add(y); // create a temporary to int
std::cout << y << "\n"; // what's the value of y ?
I'd like to call template<typename T> foo(T x) and manually handle these cases: T = std::vector<U>, T = std::string, T = any other case.
Here's what I wrote for that:
#include <iostream>
#include <vector>
#include <string>
template<typename T> void foo_impl(const std::string &data, std::string *) {
std::cout << "foo for std::string called\n";
}
template<typename T> void foo_impl(const T &data, T *) {
std::cout << "foo for general types called\n";
}
template<typename T> void foo_impl(const std::vector<T> &data, std::vector<T> *) {
std::cout << "foo for std::vector<T> called\n";
}
template<typename T> void foo(const T &data) {
foo_impl(data, static_cast<T*>(nullptr));
}
int main() {
int i = 1;
foo(i);
std::vector<int> a = {0, 1};
foo(a);
std::string s = "abcd";
foo<std::string>(s);
return 0;
}
However, foo(std::string x) is called as in case "T is any other type". How do I deal with it?
For template:
template<typename T> void foo(const T &data) {
std::cout << "foo for general types called\n";
}
Following is a specialization:
template<> void foo<>(const std::string &data) {
std::cout << "foo for std::string called\n";
}
but simple overload seems more appropriate:
void foo(const std::string &data) {
std::cout << "foo for std::string called\n";
}
As partial specialization is not possible for function, you have to make a overload for vector case:
template<typename T, typename Alloc> void foo(const std::vector<T, Alloc> &data) {
std::cout << "foo for std::vector<T, Alloc> called\n";
}
An alternative is to forward to a class/struct which can be (partially) specialized:
template <typename T>
struct foo_impl {
void operator (const T&) const
{
std::cout << "foo for general types called\n";
}
};
// specialization for std::string
template <>
struct foo_impl<std::string>
{
void operator (const T&) const
{
std::cout << "foo for std::string called\n";
}
};
// partial specialization for std::vector
template <typename T, typename A>
struct foo_impl<std::vector<T, A>>
{
void operator (const std::vector<T, A>&) const
{
std::cout << "foo for std::vector<T, A> called\n";
}
};
template <typename T>
void foo(const T& t)
{
foo_impl<T>{}(t);
}
T from template<typename T> void foo_impl(const std::string &data, std::string *) is non-deducible (that is, it's not used in the parameter list of the function), as such, it's not considered as a viable overload.
You can remove the template<typename T> part and make this overload a non-template:
void foo_impl(const std::string &data, std::string *) {
std::cout << "foo for std::string called\n";
}
It's not clear to me why you are using two layers of functions..
You can overload foo for std::string and std::vector<T>.
#include <iostream>
#include <vector>
#include <string>
template<typename T> void foo(const T &data) {
std::cout << "foo for general types called\n";
}
template <typename T> void foo(const std::vector<T> &data) {
std::cout << "foo for std::vector<T> called\n";
}
void foo(const std::string &data) {
std::cout << "foo for std::string called\n";
}
int main() {
int i = 1;
foo(i);
std::vector<int> a = {0, 1};
foo(a);
std::string s = "abcd";
foo(s);
return 0;
}
Output:
foo for general types called
foo for std::vector<T> called
foo for std::string called