2014-09-23 8 views
2


Недавно я столкнулся с проблемой с компилятором clang ++ 5.0.0, где через ADL он не собирал правильную функцию на Mac (но g ++ сделал это правильно в Linux). Я хотел бы знать, является ли его компилятор проблемой или плохой дизайн класса в целом.
Ниже приведен пример кода (чисто для иллюстрации):
Как ADL будет работать для этого?

namespace test { 
    class Ops { 
     public: 
     Ops():val_(0){} 
     template<typename T> 
     Ops& operator<< (const T& val) { 
      std::cout << "Called member function" << std::endl; 
      this->val_ = val; 
      return *this; 
     } 
     private: 
     int val_; 
    }; 

    template<typename T> 
    struct Any { 
     T val_; 
    }; 

    template <template<typename> class E, typename T> 
    Ops& operator<< (Ops& op, const E<T>& val) { 
     std::cout << "Global function" << std::endl; 
     return op; 
    } 
} 

int main() { 
    test::Ops op; 
    int k = 9; 
    test::Any<int> a; 
    op << a; 

    return 0; 
} 

Я хотел бы знать, как ADL и аргумент шаблона вычет wouldwork на шаге мудрое, чтобы найти лучший матч?
Будет ли какая-либо ситуация для того же «основного тела», что функция-член предпочтительнее вместо свободной функции? (Это то, что происходит в сборке продукта)

Заранее спасибо.

ответ

2

Это то, что происходит в деталях и то, что каждый компилятор должен делать: функция шаблон кандидата найдена квалифицированным поиском

template <typename T> 
test::Ops::operator<<(const T&) 

в то время как второй кандидат генерируется с помощью ADL с помощью аргумента шаблона дедукции (летальность темпа.. deduct.conv)

template <template <typename> class E, typename T> 
test::operator<<(test::Ops&, const E<T>&) 

После перегружать кайф разрешения в (CFR. 13.3.3) и не являющегося членом одного (F1) является предпочтительным элементом (F2) один, так как

  • F1 и F2 являются специализированными шаблонами функций, а шаблон функции для F1 более специализирован , чем шаблон для F2 в соответствии с правилами частичного упорядочения, описанными в 14.5.6.2.

и, таким образом, выбран в качестве функции для вызова.

Чтобы ответить на ваш вопрос: это зависит от правил разрешения перегрузки. Будучи членом функции или во внутреннем объеме не влияет на результат, и что-то вроде

namespace test { 
    class Ops { 
     public: 
     Ops():val_(0){} 

     template<typename T> 
     Ops& operator<< (const T& val) { 
      std::cout << "Called member function" << std::endl; 
      this->val_ = val; 
      return *this; 
     } 

     private: 
     int val_; 
    }; 

    template<typename T> 
    struct Any { 
     T val_; 
    }; 

    template <typename E> 
    Ops& operator<< (Ops& op, const E& val) { 
     std::cout << "Global function" << std::endl; 
     return op; 
    } 
} 

просто вызвать ошибку разрешения перегрузки «use of overloaded operator '<<' is ambiguous».

В качестве плюса: функция-член неверна, даже если она выбрана: this->val присваивается нецелый тип.

+1

Спасибо за отличный ответ Марко. Как вы сказали, назначение в func члена может «ошибиться», поэтому другая перегрузка, которая должна срабатывать для желаемого типа. – Arunmu

1

Эти две функции-кандидаты в наборе перегрузки:

// member function template, found by qualified lookup 
template <typename T> 
test::Ops::operator<<(const T&) 

// non-member function template, found by ADL 
template <template <typename> class E, typename T> 
test::operator<<(test::Ops&, const E<T>&) 

В операторной поиска, предпочтение не отдается членам в сравнении, не являющихся членами. После замены аргумента шаблона оба специализаций шаблонов функций точно соответствуют (с квалификационными преобразованиями) предоставленными типами аргументов. Но функция, принимающая E<T>, является более специализированным, чем тот, который принимает T, поэтому по этой причине выбрана функция, не являющаяся членом.

Apple clang 5.0.0 основан на LLVM clang 3.3svn. Я не могу найти ни одной версии LLVM clang, которая выбирает функцию-член. Это может быть ошибкой в ​​коде Apple, но IMHO, скорее всего, будет некоторой тонкой разницей в коде, который вы на самом деле компилируете, или в вашей среде. Вы пробовали компилировать свой пример кода с подозрительным компилятором?

+0

Да, пример кода работает, его просто сборка сборки происходит неправильно – Arunmu