Шаблонная перегрузка оператора не компилируется, если включены заголовки OpenCV

#c #opencv #templates #operator-overloading

#c #opencv #шаблоны #перегрузка оператора

Вопрос:

Я пытаюсь перегрузить оператор сдвига влево << для пользовательского класса, используя шаблон, и std::enable_if использовать одно объявление и определение перегрузки как для вывода на консоль / печать, так и для записи в файл:

Foo.hpp :

 #include <iostream>
#include <fstream>
#include <type_traits>
// #include <opencv2/opencv.hpp>

namespace cv {
class Foo {
 public:
    
    Foo() { }


    ~Foo() { }
    const int mb = 78;

    static bool toFile(const Fooamp; instance);
};
}

template < typename OSTR_T,
                    typename = typename std::enable_if< std::is_base_of< std::ostream, OSTR_T >::value > >
OSTR_Tamp; operator<<(OSTR_Tamp; os, const cv::Fooamp; foo);
  

и Foo.cpp :

 #include "Foo.hpp"
#include <iostream>
#include <fstream>

namespace cv {

bool Foo::toFile(const Fooamp; instance) {
    std::ofstream file("debug.txt", std::ios::app);
    file << instance;
    file.close();
    return true;
}
}  // namespace cv

template < typename OSTR_T, typename >
OSTR_Tamp; operator<<(OSTR_Tamp; os, const cv::Fooamp; foo) {
    os << foo.mb << "n";
    return os;
}

template std::ofstreamamp; operator<< < std::ofstream > (std::ofstreamamp;, const cv::Fooamp;);
template std::ostreamamp;  operator<< < std::ostream >  (std::ostreamamp;, const cv::Fooamp;);
  

Этот подход компилируется и работает нормально, однако мне нужно использовать несколько инструментов, предоставляемых OpenCV для расширения Foo , а именно объявление некоторых cv::Point и cv::Mat членов.

Как ни странно, я обнаружил, что простого включения заголовка OpenCV opencv2/opencv.hpp Foo.hpp достаточно, чтобы код больше не компилировался, и компилятор по какой-то причине становится способным находить << перегрузку:

 error: no match foroperator<<’ (operand types are ‘std::ofstream’ {aka ‘std::basic_ofstream<char>’} andconst cv::Foo’)
9 |         file << instance;
  |         ~~~~ ^~ ~~~~~~~~
  |         |       |
  |         |       const cv::Foo
  |         std::ofstream {aka std::basic_ofstream<char>}
  

Я также заметил, что это происходит только в том случае, если я объявляю Foo в cv:: namespace . Что именно здесь происходит, как включение заголовка может создать такой конфликт?

Комментарии:

1. Помимо того, о чем вы спрашиваете, мне любопытно, чего вы ожидаете достичь, используя SFINAE таким образом, вместо простого объявления шаблона, который принимает a std::ostream amp; в качестве параметра?

2. @SamVarshavchik Я на самом деле не понял, что std::ofstream это производное от std::ostream , и попытался использовать шаблонную перегрузку, чтобы соответствовать обоим. Сначала я начал с объявления перегрузки, как вы предлагаете, но получал ту же ошибку компиляции.

3. Если вы не поняли, «что std::ofstream было получено из std::ostream «, то что именно привело вас к реализации SFINAE, который использует std::is_base_of< std::ostream ... > , который проверяет именно это? Что касается причины исходной ошибки, то, вероятно, это связано с тем, что cv пространство имен определяет свою собственную << перегрузку, поэтому, как только поиск имени найдет его, он не будет пытаться выполнить разрешение перегрузки в глобальном пространстве имен. Перемещение вашей << перегрузки непосредственно в cv пространство имен, скорее всего, решит эту проблему.