друг, шаблон, пространство имен - PullRequest
0 голосов
/ 09 мая 2018

Я хочу использовать шаблонную функцию друга. Тем не менее, я не знаю, как сделать так, чтобы она работала без шаблонной функции. Вот пример кода

#include <iostream>

namespace ns{
struct Obj {
    friend void foo(Obj){std::cout << "no problem" << std::endl;}

    template<typename T>
    friend void bar(Obj){std::cout << "problem" << std::endl;}
};
}

int main() {
    ns::Obj obj;
    foo(obj); // Compile
    bar<int>(obj); // Not compile
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Простым подходом было бы добавить предварительное объявление и позволить расположению функции использовать квалифицированный поиск:

namespace ns{
struct Obj;

void foo(Obj);

template<typename T>
void bar(Obj);

struct Obj {
    friend void foo(Obj){std::cout << "no problem" << std::endl;}

    template<typename T>
    friend void bar(Obj){std::cout << "problem " << std::endl;}
};
} // namespace ns

int main() {
    ns::Obj obj;
    ns::foo(obj); // Ok
    ns::bar<int>(obj); // Ok
    return 0;
}
0 голосов
/ 09 мая 2018

До C ++ 20 вам нужно указать компилятору, что bar - это имя шаблона, чтобы он знал, что < запускает список аргументов шаблона и не является оператором меньше чем:

template<char> void bar() = delete;

int main() {
    ns::Obj obj;
    foo(obj); // Compile
    bar<int>(obj); // Now compiles too
    return 0;
}

Обратите внимание, что для перегрузки bar необходимо быть шаблоном функции . Подпись не имеет значения, если она не так хороша, чтобы мешать разрешению перегрузки; () - хороший выбор, потому что по определению мы передаем хотя бы один аргумент, поэтому шаблон функции, не имеющий параметров, никогда не сможет быть жизнеспособным.

В качестве альтернативы, вы можете изменить bar, чтобы вывести T из аргумента тега:

template<class T>
struct type {};

namespace ns{
struct Obj {    
    // ...

    template<typename T>
    friend void bar(Obj, type<T>) { /* ... */ }
};
}
// ...

bar(obj, type<int>()); // OK

В C ++ 20 компилятор будет предполагать, что bar называет шаблон, когда видит <, и поиск имени ничего не находит, поэтому ваш код просто будет работать .

...