I was tinkering to confirm the example on page 91 of Effective Modern C++, and I ran into what seems to be a strange issue. This code
template<typename C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {
std::cout << "container version" << std::endl;
}
template<>
void doStuff<int>(int& x, int& y) noexcept {
std::cout << "int version" << std::endl;
}
int main() {
vector<int> v1 = {1, 2, 3};
vector<int> v2 = {4, 5, 6};
int x = 5;
int y = 6;
doStuff(x, y);
doStuff(v1, v2);
}
Gives me an error like
error: request for member ‘front’ in ‘a’, which is of non-class type
‘int’ void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(),
b.front()))) {
So, it seems like the top version of doStuff is being called, even though a.front() and b.front() should be returning references to ints. If I remove all the noexcept declarations from the code, I get the expected output.
This is with gcc 5.4.
What am I doing wrong?
Thanks
The problem is, when the name lookup at this point:
template<typename C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {
// ^^^^^^^
will just find one doStuff(): your function template. The specialization hasn't been declared yet, so it isn't considered.
First thing to do is to simply avoid specializations. They're awkward. But then the real fix would be to stick in an extra empty type solely for argument-dependent lookup purposes. This will add a dependent name to the noexcept lookup that will delay invocation until instantiation:
namespace N {
struct adl { };
void doStuff(adl, int& , int& ) noexcept {
std::cout << "int version" << std::endl;
}
template<typename C>
void doStuff(adl, C& a, C& b) noexcept(noexcept(doStuff(adl{}, a.front(), b.front()))) {
std::cout << "container version" << std::endl;
}
}
template <class C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(N::adl{}, a, b)))
{
doStuff(N::adl{}, a, b);
}
Template specializations are not overloads. Your specialization for doStuff<int> is not an overload of doStuff<C>, it is a specialization. So overload resolution doesn't consider it, template instantiation will consider it, if the original is selected by overload resolution. Replace your specialization with an overload (non-template, taking two int&s)
void doStuff(int& a, int& b) noexcept;
Related
#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
I have been testing C++ templating within Eigen and have come across a problem while developing when using tempates and templated parameter lists.
As per the following example, the "Function 2" is printed for all calls - even though the 3rd and 4th call perfectly match the prototype. It seems that the templated parameter list takes precedence due to an ambiguity.
Now the interesting part is that this only happens when matrices are wrapped in "Eigen::MatrixBase", if I send matrices directly it is not a problem. But this would not be optimal for the expression templates being used.
Could someone explain the reason for this when using MatrixBase and what could be a workaround?
I understand that giving one function a different name will do the trick, but then the function will loose generality. Is there a better way to fix it?
Thank you for your time!
Minimal example showing the effect:
typedef Eigen::Matrix<float, 2, 2> QType;
typedef Eigen::Matrix<float, 1, 1> UType;
template <typename... ParamsType>
void fun(const Eigen::MatrixBase<QType> &Q,
const Eigen::MatrixBase<UType> &U,
const ParamsType & ...params)
{
cout << "Function 1" << endl;
}
template <typename... ParamsType>
void fun(const Eigen::MatrixBase<QType> &Q,
const ParamsType & ...params)
{
cout << "Function 2" << endl;
}
template <typename... ParamsType>
void fun2(const QType &Q,
const UType &U,
const ParamsType & ...params)
{
cout << "Function 1" << endl;
}
template <typename... ParamsType>
void fun2(const QType &Q,
const ParamsType & ...params)
{
cout << "Function 2" << endl;
}
int main(int argc, char *argv[])
{
QType Q = QType::Random();
UType U = UType::Random();
int param = 0;
fun(Q);
fun(Q, param);
fun(Q, U);
fun(Q, U, param);
fun2(Q);
fun2(Q, param);
fun2(Q, U);
fun2(Q, U, param);
return 0;
}
Output:
Function 2
Function 2
Function 2
Function 2
Function 2
Function 2
Function 1
Function 1
The reason is that UType is not the same as MatrixBase<UType>, but it inherits from it. That means passing U as a variadic parameter is closer to the function header (sorry for not being able to reference the corresponding section in the standard). See this simplified example which also illustrates the difference:
#include <iostream>
class A {};
class B {};
class C : public A { };
class D : public B { };
template<typename... P>
void fun(const A&, const B&, const P & ...p)
{
std::cout << "funAB\n";
}
template<typename... P>
void fun(const A&, const P & ...)
{
std::cout << "funAP\n";
}
int main()
{
A a;
B b;
C c;
D d;
fun(a,b); // funAB
fun(c,d); // funAP, because d only inherits from B
}
If you explicitly want "Function1" to be called when UType is passed, just write that as the parameter (as in your fun2 implementation).
I did read that C++14 generic lambdas with auto parameters are actually templates, so the following is valid C++14
auto glambda = [] (auto a) { return a; };
cout << glambda(23); // Prints 23
cout << glambda('A'); // Prints A
This doesn't quite stack up with what I know from templates.. where's the instantiation point? What is it stored in the glambda variable if the first call instantiates a template with int and the second one with char?
It's not that the "lambda is a template" -- that doesn't make sense, a lambda is an expression. Rather, the type of the closure object that's defined by the lambda expression has an overloaded function call operator that is defined by a member function template. So the instantiation point is the first use of the respective call operator.
In other words, a lambda [a, &b](auto x, auto y) -> R { /* ... */ } has a type like:
struct __lambda
{
__lambda(const A & __a, B & __b) : a(__a), b(__b) {}
template <typename T1, typename T2>
R operator()(T1 x, T2 y) const { /* ... */ }
private:
A a;
B & b;
};
A generic lambda is an object of a compiler generated type that has a template method called operator(). Your code can be rewritten with this equivalent:
struct MyLambda {
template<typename T>
T operator() (T val) {
return val;
}
};
int main() {
MyLambda func;
std::cout << func('A');
std::cout << func(42);
}
The compiler will instantiate operator() when needed.
Hope it helped
I would like to apply an overloaded function to all elements of a struct like so: (The code below will not compile)
#include <iostream>
typedef struct {
float float_val;
int int_val;
} NodeStatus;
template<typename T>
void ApplyToFields(NodeStatus *ns1, NodeStatus *ns2, void (*func)(T, T)) {
func(ns1->float_val, ns2->float_val);
func(ns1->int_val, ns2->int_val);
}
template<typename T>
void add_print(T a, T b) {
std::cout << b + a << std::endl;
}
template<typename T>
void sub_print(T a, T b) {
std::cout << b - a << std::endl;
}
int main() {
NodeStatus ns1, ns2;
ns1.float_val = 2.3;
ns2.float_val = 25.3;
ns1.int_val = 2;
ns2.int_val = 20;
ApplyToFields(&ns1, &ns2, add_print);
ApplyToFields(&ns1, &ns2, sub_print);
}
I am new to C++ coming from C. After some research I realize that passing a function pointer is probably not the correct way to do this in C++. I am interested in the best way to accomplish the same purpose as opposed to the literal question I posed which may be impossible. Solutions adhering to C++03 would be ideal. Thanks!
You can create a function object wrapping your function template (or replacing it):
struct add_printer {
template<typename T>
void operator()(T a, T b) const {
add_print(a, b);
}
};
And then use it like this:
ApplyToFields(&ns1, &ns2, add_printer());
This will delay overload resolution until add_printer's operator() is actually instantiated when it is used in ApplyToFields.
In C++14, you could use a polymorphic lambda:
[](auto a, auto b) { add_print(a, b); }
which, unlike the function object, can be defined almost anywhere, not just at namespace scope.
With your code, you have to specify which overload you want:
ApplyToFields(&ns1, &ns2, add_print<float>);
ApplyToFields(&ns1, &ns2, sub_print<int>);
or
ApplyToFields<float>(&ns1, &ns2, add_print);
ApplyToFields<int>(&ns1, &ns2, sub_print);
Demo
That you want is a generic functor
template<typename F>
void ApplyToFields(const NodeStatus &ns1, const NodeStatus &ns2, F func) {
func(ns1.float_val, ns2.float_val);
func(ns1.int_val, ns2.int_val);
}
struct add_print
{
template<typename T>
void operator() (T a, T b) {
std::cout << b + a << std::endl;
}
};
Demo
The template version is used by the compiler to calculate t = max(a, b) and max(t, c). Any quote from the Standard supporting this is welcome.
#include <iostream>
template <typename T>
inline T const& max (T const& a, T const& b)
{
std::cout << "template" << '\n';
return a < b ? b : a;
}
template <typename T>
inline T const& max (T const& a, T const& b, T const& c)
{
return max (max(a,b), c);
}
inline int const& max (int const& a, int const& b)
{
std::cout << "non-template" << '\n';
return a <b ? b : a;
}
int main()
{
std::cout << max(3, 5, 7) << '\n';
}
The code prints
template
template
7
The definition of your non-template version of max() is not visible at the call-site, it's defined afterwards. Either move that function above the 3-argument max() or add a prototype above the call-site.
int const& max (int const& a, int const& b);
Now the non-template version is chosen in both cases.
Live example
As for why this is the case, I believe §3.4.1/1 [basic.lookup.unqual] holds the answer.
In all the cases listed in 3.4.1, the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.
Note that argument-dependent name lookup does not apply in your case since the arguments to max are int, and not a user defined type. Only unqualified name lookup applies, hence, as quoted above, the lookup stops when the first match (the function template version of max()) is found.
The last sentence in the quoted section also explains why if you comment out the function template version of max() your code will not compile.