Search code examples
c++pytorchlibtorch

Why is a namespace-qualified name available as a candidate?


Using libtorch, the following snippet causes an error:

#include <iostream>
#include <torch/torch.h>
using namespace torch;
int main() {
    std::cout << zeros({}) << std::endl;
}

The compiler complains:

% g++ -lc10 -ltorch -ltorch_cpu test.cpp -o test.x                                                       
test.cpp: In function ‘int main()’:
test.cpp:5:23: error: call of overloaded ‘zeros(<brace-enclosed initializer list>)’ is ambiguous
    5 |     std::cout << zeros({}) << std::endl;
      |                  ~~~~~^~~~
In file included from /opt/links/include/ATen/Functions.h:1334,
                 from /opt/links/include/ATen/ExpandUtils.h:4,
                 from /opt/links/include/torch/csrc/autograd/input_metadata.h:3,
                 from /opt/links/include/torch/csrc/autograd/function.h:7,
                 from /opt/links/include/torch/csrc/autograd/custom_function.h:7,
                 from /opt/links/include/torch/csrc/api/include/torch/autograd.h:5,
                 from /opt/links/include/torch/csrc/api/include/torch/all.h:7,
                 from /opt/links/include/torch/csrc/api/include/torch/torch.h:3,
                 from test.cpp:2:
/opt/links/include/ATen/ops/zeros.h:35:19: note: candidate: ‘at::Tensor at::zeros(IntArrayRef, c10::TensorOptions)’
   35 | inline at::Tensor zeros(at::IntArrayRef size, at::TensorOptions options={}) {
      |                   ^~~~~
In file included from /opt/links/include/torch/csrc/api/include/torch/types.h:7,
                 from /opt/links/include/torch/csrc/api/include/torch/data/dataloader_options.h:4,
                 from /opt/links/include/torch/csrc/api/include/torch/data/dataloader/base.h:3,
                 from /opt/links/include/torch/csrc/api/include/torch/data/dataloader/stateful.h:4,
                 from /opt/links/include/torch/csrc/api/include/torch/data/dataloader.h:3,
                 from /opt/links/include/torch/csrc/api/include/torch/data.h:3,
                 from /opt/links/include/torch/csrc/api/include/torch/all.h:9:
/opt/links/include/torch/csrc/autograd/generated/variable_factories.h:565:19: note: candidate: ‘at::Tensor torch::zeros(at::IntArrayRef, c10::TensorOptions)’
  565 | inline at::Tensor zeros(at::IntArrayRef size, at::TensorOptions options = {}) {
      |                   ^~~~~

Why is at::zeros included as a candidate when I am not using namespace at?


There are many other questions about errors like this that I think don't answer my question:

  • Mistake: tried to define a function both with and without an optional/defaulted parameter
    Not relevant because: both variants were defined in the same namespace
    Questions: 1 2
  • Mistake: #include'd the C variant of a header instead of the C++ variant
    Not relevant because: libtorch does not have a C interface as far as I know
    Questions: 1 2
  • Mistake: declared the same function in two different namespaces (excitingly close!)
    Not relevant because: both namespaces have been brought into scope, one by using and one by being in that namespace right now, whereas in my case one of the claimed candidates doesn't seem like it should be in scope to me
    Questions: 1 2
  • Mistake: none of the available overloads had the right type
    Not relevant because: both candidates have the same type, and it matches the call; for example, changing zeros to torch::zeros makes the file compile
    Questions: 1 2 3

There are many, many more; I'll admit I got frustrated at this point and gave up looking through them.


Solution

  • Because the pytorch headers contain a

    using namespace at;
    

    directive inside the torch namespace. See here.

    Because you use using namespace torch; this then transitively also makes all of at available in the global scope.

    The comment above the linked line indicates that they didn't consider the user using using namespace torch; in order to make unqualified calls. It seems that they expect the user to make qualified calls instead. As the comment states, qualified lookup behaves differently.