【问题标题】:Visual Studio 2019 C++ not recognizing template friendsVisual Studio 2019 C++ 无法识别模板好友
【发布时间】:2020-11-27 00:05:18
【问题描述】:

我有一个示例 C++ 程序(包括在下面),它可以在 Visual Studio 2019 中使用普通版本的 class1 但不能使用模板版本的 class1。两个版本都在 gcc 中工作。我从 Visual Studio 2019 收到的错误消息是:

Severity:    Error
Code:        C2063
Description: 'ns1::operator *': not a function

我的问题是 Visual Studio 如何期望我在下面的示例中为模板案例声明友元运算符?

带有class1 的代码版本是一个计划类。这适用于 gcc 和 Visual Studio 2019:

# include <iostream>

// begin ns1
namespace ns1 {
    // begin class1
     class class1 {
    private:
       int value_;
    public:
       class1(int value ) : value_(value)
       { }
       int Value(void) const
       {   return value_; }
    }; // end class1
    // forward declaration or operator
     class1 operator * 
    (const class1& left, const class1& right);
    // begin ns1
    namespace ns2 {
        // begin class2
        class class2 {
            friend ns1::class1 ns1::operator * 
            (const ns1::class1& left, const ns1::class1& right);
        private:
            int value_;
        public:
            class2( int value ) : value_(value)
            { }
            int Value(void) const
            {   return value_; }
        }; // end class2
    } // end ns2
     class1 operator *
    (const class1& left, const class1 &right)
    {   ns2::class2 one(1);
    // use private access to value_ to make sure friend statement working
    return class1( one.value_ * left.Value() * right.Value() );
    }
} // end ns1

// begin main
int main(void)
{   ns1::class1 two(2), three(3);
    ns1::class1 six = two * three;
    std::cout << "six.Value() = " << six.Value() << "\n";
    return 0;
} // end main

带有class1 模板类的代码版本。这适用于 gcc,但不适用于 Visual Studio 2019。我在 Visual Studio 中使用 Hello World 控制台示例的修改版本。

# include <iostream>

// begin ns1
namespace ns1 {
    // begin class1
    template <class Type> class class1 {
    private:
       Type value_;
    public:
       class1(Type value ) : value_(value)
       { }
       Type Value(void) const
       {   return value_; }
    }; // end class1
    // forward declaration or operator
    template <class Type> class1<Type> operator * 
    (const class1<Type>& left, const class1<Type>& right);
    // begin ns1
    namespace ns2 {
        // begin class2
        class class2 {
            friend ns1::class1<int> ns1::operator * <int> 
            (const ns1::class1<int>& left, const ns1::class1<int>& right);
        private:
            int value_;
        public:
            class2( int value ) : value_(value)
            { }
            int Value(void) const
            {   return value_; }
        }; // end class2
    } // end ns2
    template <class Type> class1<Type> operator *
    (const class1<Type>& left, const class1<Type> &right)
    {   ns2::class2 one(1);
    // use private access to value_ to make sure friend statement working
    return class1<Type>( one.value_ * left.Value() * right.Value() );
    }
} // end ns1

// begin main
int main(void)
{   ns1::class1<int> two(2), three(3);
    ns1::class1<int> six = two * three;
    std::cout << "six.Value() = " << six.Value() << "\n";
    return 0;
} // end main

【问题讨论】:

  • 你能从代码中删除宏吗?很难读。 :|
  • 无法重现,显示的代码编译时没有错误或警告。
  • @anastaciu 同样在 g++-10-std=c++17 -Wall -Wextra -Wpedantic
  • 使用 3 个编译器也可以在 godbolt 上取得成功。
  • @underscore_d,这是 MSVC 的默认行为,是的 :) 但在这种情况下,我确实使用 MSVC 编译它,所以至少对于这个我们不能怪它。

标签: c++ templates visual-studio-2019 operator-keyword friend


【解决方案1】:

可在此处重现:

cl a.cpp
Microsoft (R) C/C++ Optimizing Compiler versione 19.27.29111 per x64
Copyright (C) Microsoft Corporation. Tutti i diritti  sono riservati.

a.cpp
a.cpp(22): error C2063: 'ns1::operator *': non è una funzione

也许它适用于 Godbolt,因为它有 19.24?

【讨论】:

    【解决方案2】:

    这个:

    # include <iostream>
    
    namespace ns1 {
      template <class Type> class class1 {
        private:
          Type value_;
        public:
          class1(Type value ) : value_(value) { }
          Type Value(void) const { return value_; }
      };
    
      // forward declaration or operator
      template <class Type> class1<Type> operator * (const class1<Type>& left, const class1<Type>& right);
    
      namespace ns2 {
        class class2 {
          friend class1<int> operator * <int> (const class1<int>& left, const class1<int>& right);
          private:
            int value_;
          public:
            class2( int value ) : value_(value) { }
            int Value(void) const { return value_; }
        };
      }
        
      template <class Type> class1<Type> operator * (const class1<Type>& left, const class1<Type> &right) {
        ns2::class2 one(1);
        // use private access to value_ to make sure friend statement working
        return class1<Type>( one.value_ * left.Value() * right.Value() );
      }
    }
    
    int main(void) {
      ns1::class1<int> two(2), three(3);
      ns1::class1<int> six = two * three;
      std::cout << "six.Value() = " << six.Value() << "\n";
      return 0;
    }
    

    与 g++ 一起工作:

    gcc -std=c++14 -Wall -pedantic -c b.cpp
    

    并在 friend 声明处使用 error C2063: 'ns1::operator *': non è una funzione 与 Visual Studio 2019 版本 19.27 中断。

    这个差异修复了它:

    <       friend class1<int> operator * <int> (const class1<int>& left, const class1<int>& right);
    ---
    >       template <class Type> friend class1<Type> ns1::operator * (const class1<Type>& left, const class1<Type>& right);
    

    注意:这只发生在operator *,如果我尝试operator +,就不需要使用通用模板......奇怪!

    【讨论】:

      【解决方案3】:

      我把它归结为一个简单的复制案例。

      namespace Some
      {
      
      // Forward declarations.
      template <typename T> class Stuff;
      template <typename T> class Thing;
      template <typename T> Stuff<T> operator*( const Stuff<T>& lhs, const Thing<T>& rhs );
      template <typename T> Thing<T> operator*( const T& s, const Thing<T>& rhs );
      
      // Class definition.
      template <typename T>
      class Thing
      {
      #if 0
          template<typename U> friend typename std::enable_if<std::is_same<T, U>::value, Stuff<U> >::type operator*(const Stuff<U>& lhs, const Thing<U>& rhs);
          template<typename U> friend typename std::enable_if<std::is_same<T, U>::value, Thing<U> >::type operator*(const U& s, const Thing<U>& rhs);
      #else
          friend Stuff<T> Some::operator* <T>( const Stuff<T>& lhs, const Thing<T>& rhs );
          friend Thing<T> Some::operator* <T>( const T& s, const Thing<T>& rhs );
      #endif
      };
      
      } //namespace Some
      
      int
      main(int argc, char** argv)
      {
          Some::Thing<float> mat;
          return 0;
      }
      

      这在 VS2010、VS2017、gcc/MinGW 和 clang/MinGW 上构建良好,但 VS2019 会产生虚假错误。

      我已将此作为 bug 提交给 Microsoft。

      顺便说一句,注释掉的版本也适用于所有编译器,并确保友元函数只为相同类型定义,但显然要冗长得多。

      【讨论】:

        猜你喜欢
        • 2020-03-22
        • 1970-01-01
        • 2015-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-26
        相关资源
        最近更新 更多