Search code examples
c++argument-dependent-lookup

C++ ADL of a function in another namespace


I have a function template printSize calling the overloaded function getSize before getSize is declared. For a clearer structure of my program, I would like to put both functions in different namespaces A and B, as the commented code lines show. However, ADL will then fail to find getSize.

Actually, printSize and getSize are implemented in different header files. Therefore, I cannot put a using namespace directive.

#include <array>
#include <iostream>
#include <string>

namespace A {

template <typename T> struct tag {};

template <typename T>
void printSize(const T &data)
{
    size_t data_size = getSize(data, tag<T>{});
    //size_t data_size = B::getSize(data, tag<T>{});
    std::cout << "Size: " << data_size << std::endl;
}

//} // namespace A

//namespace B {

constexpr size_t getSize(const int &, tag<int>)
{
    return sizeof(int);
}

size_t getSize(const std::string &str, tag<std::string>)
{
    return str.size();
}

template <typename T, size_t N>
size_t getSize(const std::array<T, N> &array, tag<std::array<T, N>>)
{
    size_t array_size = 0;
    for (const T &element : array)
        array_size += getSize(element, tag<T>{});
    return array_size;
}

} // namespace A/B

int main()
{
    int a;
    A::printSize(a);

    std::array<std::string, 2> arr = {{"foo", "foobar"}};
    A::printSize(arr);

    return 0;
}

Is there a way to make this code compile with printSize and getSize being defined in different namespaces?


Solution

  • One solution would be to put the tag into the B namespace, and pull it into A.

    namespace B {
        template <typename T> struct tag {};
    }
    
    namespace A {
       using B::tag;
    }
    

    Now, because tag comes from the B namespace, it will associate B for ADL.