initializer_list and argument-dependent lookup - c++

I'm trying to use an std::initializer_list as an argument in a function that uses argument-dependent lookup (ADL). But I don't get it to work and I don't understand why. The following is a minimal failing example:
#include <initializer_list>
#include <iostream>
class Foo {
public:
inline friend void bar(std::initializer_list<Foo> v) {
std::cout << "size = " << v.size() << std::endl;
}
};
void baz(std::initializer_list<Foo> v) {
std::cout << "size = " << v.size() << std::endl;
}
int main(){
Foo a;
//bar({a,a}); // error: use of undeclared identifier 'bar'
baz({a,a}); // works
return 0;
}
As seen above, an equivalent global function works just fine. Why does the above not work?
I'm using clang on OS X 10.10.

I believe that the problem is that the subexpression1 { a, a } does not really have a type, and as such it does not have associated types or namespaces which in turn means that ADL does not kick in. If you have a function in the global namespace, normal lookup will find it, and it will find that { a, a } can match the function call as the initializer for std::initializer_list<Foo>.
1 The syntax { a, a } is called braced-init-list and it is not really an expression (or subexpression) in the language.

When the compiler sees bar({a,a}), it doesn't know the type of the arguments, so it searches for bar in the global namespace (::), and nowhere else. If you changed that line to Foo{a,a}, then it knows the argument is a Foo, and so also searches the Foo class for functions.

Related

Reusing user-defined function pointer type to declare a function [duplicate]

So given a typedef that defines a function pointer with parameter names like this:
typedef void(*FOO)(const int arg);
Is there a way that I can just use this function pointer to define the signature of my function? Obviously this won't work, but I'd like to somehow use the typedef to specify a function signature with a corresponding type:
FOO foo {
cout << arg << endl;
}
Again, I know this doesn't work, and is bad syntax. It will just give the error:
error: arg was not declared in this scope
What you are trying to do will not work. FOO is an alias for void(*)(const int). so
FOO foo {
cout << arg << endl;
}
becomes
void(*)(const int) foo {
cout << arg << endl;
}
and that just doesn't work. What you can do though is define a macro that takes a name and use that to stamp out a function signature. That would look like
#define MAKE_FUNCTION(NAME) void NAME(const int arg)
MAKE_FUNCTION(foo){ std::cout << arg * 5 << "\n"; }
MAKE_FUNCTION(bar){ std::cout << arg * 10 << "\n"; }
int main()
{
foo(1);
bar(2);
}
The definition of a function pointer has nothing to do with the declaration nor the definition of a function so the answer is no.
You can do this actually. You can abuse lambdas to clone a function by assigning an auto lambda to the type. The downside is you lose access to the argument names, and have to access the arguments by index instead.
https://github.com/stevemk14ebr/PolyHook_2_0/blob/350f6723f0c12b93085273fc4a5208aaa36bf41a/polyhook2/IHook.hpp#L67-L150
here's an example of the usage
https://github.com/stevemk14ebr/PolyHook_2_0/blob/350f6723f0c12b93085273fc4a5208aaa36bf41a/UnitTests/windows/TestDetourx64.cpp#L22-L41

Why does endl(std::cout) compile

Surprisingly the below code compiles and runs without error on a variety of compilers and versions.
#include <iostream>
int main() {
endl(std::cout);
return 0;
}
Ideone link
How does it compile? I am sure there is no endl in global scope because a code like
std::cout << endl;
would fail unless using is used or else you need std::endl.
This behavior is called argument dependent lookup or Koenig lookup. This algorithm tells the compiler to not just look at local scope, but also the namespaces that contain the argument's type while looking for unqualified function call.
For ex:
namespace foo {
struct bar{
int a;
};
void baz(struct bar) {
...
}
};
int main() {
foo::bar b = {42};
baz(b); // Also look in foo namespace (foo::baz)
// because type of argument(b) is in namespace foo
}
About the piece of code referred in question text:
endl or std::endl is declared in std namespace as following:
template< class CharT, class Traits >
std::basic_ostream<charT,traits>& endl( std::basic_ostream<CharT, Traits>& os );
or
std::ostream& endl (std::ostream& os);
And cout or std::cout is declared as
extern std::ostream cout;
So calling std::endl(std::cout); is perfectly fine.
Now when one calls just endl(std::cout);, because the type of argument cout is from std namespace, unqualified supposedly a function endl is searched in std namespace and it is found succesfully and confirmed to be a function and thus a call to qualified function std::endl is made.
Further reading:
GOTW 30: Name Lookup
Why does 'std::endl' require the namespace qualification when used in the statement 'std::cout << std::endl;", given argument-dependent lookup?
It is the way the stream manipulators work.
Manipulators are functions that passed to operator << as arguments. Then within the operator they are simply called.
So you have function declared like
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
and you pass its pointer to operator <<. And inside the operator that declared something like
ostream& ostream::operator << ( ostream& (*op)(ostream&));
the function is called.like
return (*endl )(*this);
Thus when you see record
std::cout << std::endl;
then std::endl is function pointer that is passed to the operator << as argument.
In the record
std::endl( std::cout );
namespace prefix before name endl may be omitted because in this case the compiler will use the Argument Dependent Lookup. Thus this record
endl( std::cout );
will compile successfully.
However if to enclose the function name in parentheses then ADL is not used and the following record
( endl )( std::cout );
will not compiled.

I don't understand 3.4/2 in the Standard

I don't understand 3.4/2 in the Standard:
A name “looked up in the context of an expression” is looked up as an
unqualified name in the scope where the expression is found.
What if the name is qualified, as N::i below?
#include <iostream>
namespace N { int i = 1; }
int main()
{
int i = 0;
std::cout << N::i << '\n';
}
The qualified name N::i is not looked up in the scope where N::i is found, i.e., it's not looked up in the scope of main() and the global scope!
To expand on the comment by #JerryCoffin, the rules for qualified lookup are:
3.4.3 Qualified name lookup [basic.lookup.qual]
3 In a declaration in which the declarator-id is a qualified-id, names
used before the qualified-id being declared are looked up in the
defining namespace scope; names following the qualified-id are looked up
in the scope of the member’s class or namespace.
Here's an example:
#include <iostream>
struct N { enum { i = 1 }; };
int main()
{
std::cout << N::i << '\n'; // prints 1
struct N { enum { i = 0 }; };
std::cout << N::i << '\n'; // prints 0
}
Live Example.
First the left-hand side of :: is looked up, and then the right-hand side is looked up inside it. So, to look up N::i, first it finds N using unqualified lookup, then it looks inside N to find i. Simple!
In your example, you redefine N locally. After the local definition, the outer definition is hidden per §3.3.10: "A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class."
Since the compiler knows at the outset that the left-hand side (N) must yield a type, namespace, or enumeration, any other lookup results (i.e. functions, variables, and templates) are ignored. So, you could also do:
#include <iostream>
struct N { enum { i = 1 }; };
int main()
{
int N = 3;
std::cout << N::i << '\n'; // prints 1
std::cout << N << '\n'; // prints 3
struct N { enum { i = 0 }; };
std::cout << N::i << '\n'; // prints 0
}
http://coliru.stacked-crooked.com/a/9a7c9e34b1e74ce7
See §3.4.3/1:
The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator (5.1) applied to a nested-name-specifier that denotes its class, namespace, or enumeration. If a :: scope resolution operator in a nested-name-specifier is not preceded by a decltype-specifier, lookup of the name preceding that :: considers only namespaces, types, and templates whose specializations are types. If the name found does not designate a namespace or a class, enumeration, or dependent type, the program is ill-formed.

Why can't my trait template class lookup operator<< for llvm::StringRef?

Following the question How can I detect if a type can be streamed to an std::ostream? I've written a trait class that says if some type can be streamed to an IO stream. The trait has seemed to work well until now that I've discovered a problem.
I'm using the code inside a project that uses LLVM and I'm using their StringRef class (which is similar in spirit to the proposed std::string_view). Here is a link to the Doxygen doc for the class, from where you can find it's declaration header file if needed. Since LLVM doesn't provide an operator<< to stream StringRef objects to std streams (they use a custom lightweight stream class), I've written one.
However, when I use the trait it doesn't work if my custom operator<< is declared after the trait (this happens because I have the trait in one header and the operator<< function in another one). I used to think that the lookup in template instantiations worked from the point of view of the instantiation point, so I thought it should work. Actually, as you can see below, with another class and its custom operator<<, declared after the trait, everything works as expected (that's why I've discovered this problem only now), so I can't figure out what makes StringRef special.
This is the complete example:
#include <iostream>
#include "llvm/ADT/StringRef.h"
// Trait class exactly from the cited question's accepted answer
template<typename T>
class is_streamable
{
template<typename SS, typename TT>
static auto test(int)
-> decltype(std::declval<SS&>() << std::declval<TT>(),
std::true_type());
template<typename, typename>
static auto test(...) -> std::false_type;
public:
static const bool value = decltype(test<std::ostream,T>(0))::value;
};
// Custom stream operator for StringRef, declared after the trait
inline std::ostream &operator<<(std::ostream &s, llvm::StringRef const&str) {
return s << str.str();
}
// Another example class
class Foo { };
// Same stream operator declared after the trait
inline std::ostream &operator<<(std::ostream &s, Foo const&) {
return s << "LoL\n";
}
int main()
{
std::cout << std::boolalpha << is_streamable<llvm::StringRef>::value << "\n";
std::cout << std::boolalpha << is_streamable<Foo>::value << "\n";
return 0;
}
Contrary to my expectations, this prints:
false
true
If I move the declaration of the operator<< for StringRef before the trait declaration, it prints true.
So why is this strange thing happening and how can I fix this issue?
As mentioned by Yakk this is simply ADL: Argument Dependent Lookup.
If you don't want to bother, just remember that you should always write a free function in the same namespace as at least one of its arguments. In your case, since it's forbidden to add functions to std, it means adding your function into the llvm namespace. The fact that you needed to qualify the StringRef argument with llvm:: was a dead give away.
The rules of function resolution are fairly complex, but as a quick sketch:
name lookup: collects a set of potential candidates
overload resolution: picks the best candidate among the potentials
specialization resolution: if the candidate is a function template, check for any specialization that could apply
The name lookup phase which we are concerned with here is relatively simple. In short:
it scans the argument's namespaces, then their parents, ... until it reaches the global scope
then proceeds by scanning the current scope, then its parent scope, ... until it reaches the global scope
Probably to allow shadowing (like for any other name lookup), the lookup stops at the first scope in which it encounters a match, and haughtily ignore any surrounding scope.
Note that using directives (using ::operator<<; for example) can be used to introduce a name from another scope. It is burdensome though, as it puts the onus on the client, so please don't rely on its availability as an excuse for sloppiness (which I've seen done :x).
Example of shadowing: this prints "Hello, World" without raising an ambiguity error.
#include <iostream>
namespace hello { namespace world { struct A{}; } }
namespace hello { void print(world::A) { std::cout << "Hello\n"; } }
namespace hello { namespace world { void print(A) { std::cout << "Hello, World\n"; } } }
int main() {
hello::world::A a;
print(a);
return 0;
}
Example of interrupted search: ::hello::world yielded a function named print so it was picked out even though it does not match at all and ::hello::print would have been a strictly better match.
#include <iostream>
namespace hello { namespace world { struct A {}; } }
namespace hello { void print(world::A) { } }
namespace hello { namespace world { void print() {} } };
int main() {
hello::world::A a;
print(a); // error: too many arguments to function ‘void hello::world::print()’
return 0;
}

Overload resolution resolves to a function not visible yet

This is kind of a follow on to this question.
#include <iostream>
struct type1 {};
struct type2 {};
void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<type1>();
bar<type2>();
return 0;
}
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
In the above code foo(type2) is not visible at the time of instantiation of bar<type2> in main. And yet the code compiles and produces the following output :
foo(type1)
foo(type2)
How does the compiler know that foo(type2) is available when instantiating bar<type2> in main?
EDIT : I am trying to understand more about how overload resolution during template instantiation works. Consider the code below :
#include <iostream>
struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};
void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
int main()
{
foo(type3());
return 0;
}
void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}
The output is
foo(type2)
Even though a closer match foo(type3) is available, the call foo(type3()) resolves to foo(type2) because that was the only candidate that has been parsed by the compiler until that point. Now consider the following code :
#include <iostream>
struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<type3>();
return 0;
}
void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}
The output is
foo(type3)
That is, at the point of the call bar<type3>(), even though only foo(type2) is visible, the compiler still picks foo(type3) that comes later because that is a closer match.
Any symbol left without a definition is to be replaced during the linking process, since the function foo(type2) could've been provided in another file.
The compiler is to say whether the function needed has been defined by the end of the entire process, when no further substitution can be applied.
In order to clarify the understanding, you must be aware of the steps required to compile, say, a common C program:
first, you expand all the macros on your code;
then your code is validated according to the language syntax, so that it can be converted into assembly language -- the compilation process itself; during this step, every symbol found without a definition is annotated in a table with the entries (symbol, definition), that shall be completed later, allowing your program to be constructed properly;
next, your code compiled into assembly will be converted to machine language, i.e., the objects will be created;
finally, you need to link your already executable objects, in order to solve any dependencies on symbol definitions; this last step checks your objects for undefined symbols, adding definitions from other modules or from libraries, thus, completing the program.
If any symbol was not correctly "linked" to its definition, the compiler will point out an error in your program -- the classic undefined reference to....
Considering the code you've posted, the process would be executed until it reaches the compiler. The compiler would traverse the code, notice the definition of type1, type2, foo(type1 x), and bar<T>().
struct type1 {};
struct type2 {};
When it'd reached the main, it would find the call for bar<type1>();, and would call foo(type1()), which is already known, and can be used properly.
void foo(type1 x) {
std::cout << "foo(type1)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main() {
bar<type1>();
bar<type2>();
return 0;
}
Once it'd reached the next call, bar<type2>();, it would try to call foo(type2()), but no such definition would be available for usage, so it would relate this call as an unknown symbol, that must be replaced by a definition in the later processes.
After the compiler runs through the main, it reaches a new definition, that is exactly the one lacking definition on the "translation table" being created.
void foo(type2 x) {
std::cout << "foo(type2)" << std::endl;
}
So, in the next step, the compilation is able to replace the symbol with its respective definition, and the program compiles correctly.
Regards!
The answer is found via argument-dependent name lookup (ADL) (which is also mentioned in the linked question). foo(T()); has two lookups. First at template definition time, any functions defined at the point of definition are included in the overload set. This means when the compiler sees foo(T()); inside of bar, it adds only void foo(type1 x) to the overload set. However there is a second lookup that is performed, called ADL. At template instantiation time, i.e. bar<type2>(); it looks for a foo in the same namespace as the argument which is provided, which in this case is type2. Since type2 is in the global namespace, it looks for a foo that takes a type2 in the global namespace and finds it, and resolves the call. If you are looking for info from the standard, see 14.6.4.2 Candidate functions.
Try the following and watch the code fail. This is because it cannot find foo in the same namespace as a::type1.
#include <iostream>
namespace a
{
struct type1 {};
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<a::type1>();
return 0;
}
void foo(a::type1 x)
{
std::cout << "foo(a::type1)" << std::endl;
}