I was messing around with some code when this weird behavior occurred :
In the first test, base templated function, user and templated specialization lie within the same namespace and it behaves as I expect :
namespace Test1
{
template <typename V, typename T>
int doFoo(V& a_visitor, T& a_value)
{
return 0;
}
struct Foo
{
template <typename T>
int process(T const& a_value)
{
return doFoo(*this, a_value);
}
};
template <typename T>
int doFoo(Foo& a_vis, T const& a_ptr)
{
return 1;
}
}
int main()
{
int const k{ 42 };
return Test1::Foo{}.process(k); // returns 1
}
but when I move base templated function and its specialization in another namespace, the base one is selected :
namespace Test2
{
namespace b
{
template <typename V, typename T>
int doBar(V& a_visitor, T& a_value)
{
return 0;
}
}
struct Bar
{
template <typename T>
int process(T const& a_value)
{
return b::doBar(*this, a_value);
}
};
namespace b
{
template <typename T>
int doBar(Bar& a_vis, T const& a_ptr)
{
return 1;
}
}
}
int main()
{
int const k{ 17 };
return Test2::Bar{}.process(k); // returns 0
}
EDIT I can do even weirder : in example 1 if I replace call to doFoo with Test1::doFoo I get the wrong behavior again !
Could anyone explain me what is going on here ? How can I do if I really need struct Bar not to be within namespace b ?
To begin with, those aren't specializations, those are overloads. Completely different function templates that aren't related to each other.
The behavior you see is consistent with argument-dependent lookup. When encountering an unqualified function call, the compiler builds an overload set by examining the namespaces associated with each argument to the function call.
Normally this won't find declarations the come "after", but templates are special. In templates lookup for a dependent name, such as a function call that depends on a template parameter (the type of a_value), is performed after the template is instantiated, and not at the point of definition. That occurs in main, after the namespace is complete and all overloads are available, and so ADL finds the second overload.
This is also why when you qualify the call by Test1 you no longer find the second overload. That negates ADL, and only allows for overloads that appear prior to the point of the call. The easiest way to resolve it would probably be to delay the definition of process until all overloads are available, as other answers indicate.
Related
I have a template class where I would like to remove a member function if the type satisfies some condition, that, as far as I understand, should be a very basic usage of SFINAE, for example:
template<class T>
class A
{
public:
template<typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
T foo () {
return 1.23;
}
};
However, this is results in an error "no type named 'type'", like SFINAE was not going on. This however works if foo is a function not member of a class. What is wrong with this implementation?
You're missing a dependent name for the compiler to use for SFINAE. Try something like this instead:
#include <type_traits>
template<class T>
class A
{
public:
template<typename Tp = T>
typename std::enable_if<std::is_floating_point<Tp>::value, Tp>::type
foo () {
return 1.23;
}
};
int main() {
A<double> a;
a.foo();
}
If the type T is not floating point, the declaration would be malformed (no return type) and the function would not be considered for the overload set.
See it on godbolt.
Why am I getting an error message when calling unary + with operator syntax? If I call it with function syntax, it is OK. Live demo.
template <int size>
struct Buffer { char buf[size]; };
template <class T>
struct Wrapper { void operator+() {} };
Wrapper<Buffer<-5>> a;
void f1() { +a; } // error: Buffer<-5>::buf has negative size
void f2() { a.operator+(); } // OK
The unqualified lookup invokes ADL, which needs to know if there are any friend functions defined in the associated classes. Buffer<-5> is one such, so it is instantiated. The fact that it’s syntactically obvious that it declares no friends doesn’t change the fact that the check for same involves completing the class type, which fails.
As an example let's put Buffer into namespace N, and operator+ into Buffer. If a's type is Wrapper<N::Buffer<5>> (5 rarher than -5), operator+ is found by ADL, and the code compiles (live demo):
template <class T>
struct Wrapper {};
namespace N {
template <int size>
struct Buffer {
template <class T> friend void operator+(const Wrapper<T>&) {}
char buf[size];
};
}
Wrapper<N::Buffer<5>> a;
void f1() { return +a; }
I know I cannot use a namespace as a template parameter. However, I'm trying to achieve behavior similar to this:
template <typename T>
void foo(T::X* x)
{
T::bar(x);
}
Except T is a namespace rather than a struct or a class. What is the best way to achieve the most similar result to what I am expecting?
Except T is a namespace rather than a struct or a class. What is the best way to achieve the most similar result to what I am expecting?
Don't mention T at all.
template <typename X>
void foo(X* x)
{
bar(x);
}
ADL will always pick up on overloads from the namespace where X is defined. Let the mechanism do its work.
Now, if you are asking how to make the compiler favor functions found by ADL, it's all about manipulating overload resolution. We can do that by limiting what is picked up by regular unqualified name lookup:
namespace foo_detail {
void bar(...);
template<typename X>
void foo_impl(X* x) {
bar(x);
}
}
template <typename X>
void foo(X* x)
{
foo_detail::foo_impl(x);
}
When the call in foo_detail::foo_impl is trying to resolve bar, the first phase in two-phase lookup will pickup the C variable argument function. Now lookup stops, no further enclosing namespaces will be looked in. Which means that only ADL can offer more candidates. And due to how overload resolution works, a C-style variable argument function like we added will be a worse match than anything ADL will find.
Here's a live example for all of this at work.
Namespace can't be a template parameter.
The only possible template parameters are:
types
and values which are: Template parameters and template arguments - cppreference.com
std::nullptr_t (since C++11);
an integral type;
a pointer type (to object or to function);
a pointer to member type (to member object or to member function);
an enumeration type.
So if you want change bar version depending on namespace it can't be done like you proposed.
It can be achieved if bar is enclosed in class as a static function. In such case you can use your template, then that class becomes template parameter.
So your code can look lie this:
class Variant1 {
public:
typedef int* argType;
static void bar(argType i) {
std::cout << (*i + 1);
}
};
class Variant2 {
public:
typedef size_t* argType;
static void bar(argType i) {
std::cout << (*i - 1);
}
};
template <typename T>
void foo(typename T::argType x)
{
T::bar(x);
}
//usage
size_t a = 1;
int x = 1;
foo<Variant1>(&a);
foo<Variant2>(&b);
I can't seem to call a method of a base class without scoping to the base class, and it seems that this is because I have overloaded the method. If I do not overload the method then the compiler doesn't complain. Here's an example of what I'd like to do:
struct BaseClass {
template <typename T> T& foo(T& t) {
return t;
}
};
class ChildClass: public BaseClass {
public:
// The presence of this template causes compiler confusion
template <class T> T& foo(T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
// But if I scope this as BaseClass::foo(...) it's all good
return foo(t);
}
};
int main() {
int t = 1;
ChildClass c;
c.bar(t);
}
If in bar(...) I call BaseClass::foo(...) the compiler does not complain, but I don't see any ambiguity here and so I'm confused as to why I'd need to do this.
When the compiler tries to match a function name with a function, it does so in two steps. In the first step it finds all the functions that match the given name. If it finds more than one function, it tries the logic of overload resolution to find the best matching function.
In the first step, if the compiler finds a name in the class, it stops looking for functions of the same name in base classes. In your case, since it finds a foo in ChildClass, it stops searching for functions named foo in BaseClass. However, the only matching foo does not match the call and the compiler reports an error.
How to resolve the problem:
Use the method you described in your post. Call BaseClass::foo(...).
Bring all the foo from BaseClass into the scope of ChildClass.
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
return sizeof(foo(1, t)); // Should work.
}
};
From the C++ standard 3.3.10 paragraph 1 :
A name can be hidden by an explicit declaration of that same name in
a nested declarative region or derived class
ChildClass::foo shadows the definition of BaseClass::foo. All you need to bring it into scope is a using directive:
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl);
};
You need a using, like:
using BaseClass::foo;
I have a struct called Vector2 which has a template parameter of T.
(vector2.h)
template <typename T>
struct Vector2
{
T Values[2];
// ..... methods .....
};
I have a method called abs() which is a wrapper to the std::abs() function for most types.
(mymath.h)
template <typename T>
static T abs(const T value)
{
return std::abs<T>(value);
}
If I try and pass the vector2 struct to abs() it won't work because the template specialization used in std doesn't include a method for it... obviously, I created it :)
I want to create one.
How can I create a template specialization for a method that takes a struct that requires it's own template parameter?
This was my best guess, but it isn't valid syntax. Is it even possible?
(mymath.cpp)
template <typename T>
static Vector2<T> abs<Vector2<T>>(const Vector2<T>& vector)
{
return vector.abs(); //this exists
}
Function template can only be fully specialized. You can't partially specialize a function template. However, you can specialize class templates and have a static member in such a class:
template <typename T>
struct abs_helper {
static T abs(T const value) { return std::abs(value); }
};
template <typename T>
struct abs_helper<Vector2<T>> {
static Vector2<T> abs(Common::Vector2<T> const& matrix) { return matrix.abs(); }
};
template <typename T>
auto abs(T&& value)
-> decltype(abs_helper<std::remove_const_t<std::remove_reference_t<T>>>::abs(std::forward<T>(value))) {
return abs_helper<std::remove_const_t<std::remove_reference_t<T>>>::abs(std::forward<T>(value));
}
The forwarding is a bit complicate given that your code uses different approaches to pass arguments for the two different functions: the code tries to mimick this forward (I haven't tried to compile it).
Just to explain a bit what's going on:
The struct abs_helper is a class template which can be partially specialized and is partially specialized for Vector2<T>. The specialization is required to have a static member called abs() taking a suitable argument and returning the desired result.
The function template abs() just forwards to abs_helper<...>::abs(...). Since it forwards its argument it uses prefect forwarding. There are to complications with this forwarding, though:
The template argument deduced for abs() may contain a reference and/or a const which need to be removed before passing it on to the specialized abs_helper (otherwise it would require multiple specialization). Thus, any reference is removed followed by removing any const using the C++14 type traits using alias (std::remove_reference_t<T> and std::remove_const<T>).
The return type seems to differ. To deal with that the code uses C++11 return-type specification combined with determining the type using decltype() based on the actual call of the function.
Not being a c++11 guy, my answer looks a bit different and less scientific. You be the judge if this is what you need. I theorized that your Vector2 version of abs would return the length of the vector. As such, the return value of your Vector2::abs would not be T but double (or float or long) depending on what you need, independent of T for your input arguments. Here is my complete test code for that case...
#include "stdafx.h"
#include <iostream>
#include <cmath>
namespace Common
{
template <typename T>
struct Vector2
{
T Values[2];
// ..... methods .....
double abs() const
{
return std::sqrt(Values[0] * Values[0] + Values[1] * Values[1]);
}
};
}
template <typename T>
static T abs(const T value)
{
return std::abs(value);
}
template <typename T>
static double abs(const Common::Vector2<T>& matrix)
{
return matrix.abs();
}
int _tmain(int argc, _TCHAR* argv[])
{
Common::Vector2<float> v1;
v1.Values[0] = 1.0F;
v1.Values[1] = 1.0F;
std::cout << "Result = " << abs(v1) << std::endl;
return 0;
}