GCC 不能使用未定义的运算符=

GCC can't use undefined operator=

本文关键字:运算符 未定义 不能 GCC      更新时间:2023-10-16
我有一个代码:
#define CLI_DECLARE_PROPERTY_RW(OWNERNAME, TYPE, NAME)                   
struct propclass_##NAME {                                                
    DWORD dummy;                                                         
    inline operator TYPE() {                                             
        return CLI_CONTAINING_RECORD(this, OWNERNAME, NAME)-> get_##NAME ();    
    }                                                                    
    inline void operator=(const TYPE &src) {                             
        CLI_CONTAINING_RECORD(this, OWNERNAME, NAME)-> set_##NAME (src); 
    }                                                                    
} NAME;
...
    class CiStringSpecialEncoderWrapper
    {
        public:
        CLI_DECLARE_PROPERTY_RW(CiStringSpecialEncoderWrapper, INTERFACE_CLI_ISTRINGENCODER*, defEncoder)
...
specialEncoderText.defEncoder = encoder.getIfPtr(); // getIfPtr returns exact  INTERFACE_CLI_ISTRINGENCODER*

并得到一个错误:

error: no match for 'operator=' in 'specialEncoderText.cli::CiStringSpecialEncoderWrapper<cli::CCliPtr<cli::iStringSpecialEncoder> >::defEncoder = encoder.cli::CiStringEncoderWrapper<smartPtrType>::getIfPtr [with smartPtrType = cli::CCliPtr<cli::iStringEncoder>]()'
note: candidates are: void cli::CiStringSpecialEncoderWrapper<smartPtrType>::propclass_defEncoder::operator=(const cli::iStringEncoder*&) [with smartPtrType = cli::CCliPtr<cli::iStringSpecialEncoder>]
note:                 cli::CiStringSpecialEncoderWrapper<cli::CCliPtr<cli::iStringSpecialEncoder> >::propclass_defEncoder& cli::CiStringSpecialEncoderWrapper<cli::CCliPtr<cli::iStringSpecialEncoder> >::propclass_defEncoder::operator=(const cli::CiStringSpecialEncoderWrapper<cli::CCliPtr<cli::iStringSpecialEncoder> >::propclass_defEncoder&)

似乎GCC试图使用默认的隐式操作符=,这是未定义的。我怎样才能解决这个问题?

我尝试用第二个签名定义private operator=,但仍然存在歧义。

当前使用的GCC版本是4.4.1。以前使用的是GCC v3.4,这段代码没有问题。

UPD01最小、完整和可验证的示例

#include <iostream>
typedef unsigned long DWORD;
typedef unsigned long ULONG_PTR;
typedef char * PCHAR;
#if defined(_MSC_VER) || defined(DISABLE_GCC_OFFSETOF_WARNING_WORKAROUND)
    #define CLI_CONTAINING_RECORD(address, type, field) ((type *)( 
                                                      (PCHAR)(address) - 
                                                      (ULONG_PTR)(&((type *)0)->field)))
#else
    #define CLI_CONTAINING_RECORD(address, type, field) ((type *)( 
                                                      1+(PCHAR)(address) - 
                                                      (ULONG_PTR)(&((type *)1)->field)))
#endif

#define CLI_DECLARE_PROPERTY_RW(OWNERNAME, TYPE, NAME)                   
struct propclass_##NAME {                                                
    DWORD dummy;                                                         
    /*propclass_##NAME() : dummy() {}*/                                      
    inline operator TYPE() {                                             
        return CLI_CONTAINING_RECORD(this, OWNERNAME, NAME)-> get_##NAME ();    
    }                                                                    
    inline void operator=(const TYPE &src) {                             
        CLI_CONTAINING_RECORD(this, OWNERNAME, NAME)-> set_##NAME (src); 
    }                                                                    
    /*private:*/                                                             
    /*explicit propclass_##NAME(const propclass_##NAME &src) {} */            
    /*inline void operator=(const propclass_##NAME &src) {}     */           
                                                                         
} NAME;

struct SomeInterface
{
 int dummy;
 void doJob() { std::cout<<"SomeInterface::doJobn"; }
};
class CTest
{
    SomeInterface *psf;
 public:
    SomeInterface* get_defEncoder( )
       {
        return psf;
       }
    void set_defEncoder( const SomeInterface*  &_defEncoder
                       )
       {
        psf = (SomeInterface*)_defEncoder;
       }
    CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
};
SomeInterface sf;
int main(int argc, char* argv[])
{
    CTest test;
    test.defEncoder = &sf; // (SomeInterface*)0;
    SomeInterface *pif = test.defEncoder;
    pif->doJob();
}

g++ 4.9.0为您的MCVE提供了以下错误:

main.cpp:58:64: warning: extra ';' [-Wpedantic]
     CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
                                                                ^
main.cpp: In function 'int main(int, char**)':
main.cpp:68:21: error: no match for 'operator=' (operand types are 'CTest::propclass_defEncoder' and 'SomeInterface*')
     test.defEncoder = &sf; // (SomeInterface*)0;
                     ^
main.cpp:68:21: note: candidates are:
main.cpp:25:17: note: void CTest::propclass_defEncoder::operator=(const SomeInterface*&)
     inline void operator=(const TYPE &src) {                             
                 ^
main.cpp:58:5: note: in expansion of macro 'CLI_DECLARE_PROPERTY_RW'
     CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
     ^
main.cpp:25:17: note:   no known conversion for argument 1 from 'SomeInterface*' to 'const SomeInterface*&'
     inline void operator=(const TYPE &src) {                             
                 ^
main.cpp:58:5: note: in expansion of macro 'CLI_DECLARE_PROPERTY_RW'
     CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
     ^
main.cpp:19:8: note: CTest::propclass_defEncoder& CTest::propclass_defEncoder::operator=(const CTest::propclass_defEncoder&)
 struct propclass_##NAME {                                                
        ^
main.cpp:58:5: note: in expansion of macro 'CLI_DECLARE_PROPERTY_RW'
     CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
     ^
main.cpp:19:8: note:   no known conversion for argument 1 from 'SomeInterface*' to 'const CTest::propclass_defEncoder&'
 struct propclass_##NAME {                                                
        ^
main.cpp:58:5: note: in expansion of macro 'CLI_DECLARE_PROPERTY_RW'
     CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
     ^
main.cpp:19:8: note: CTest::propclass_defEncoder& CTest::propclass_defEncoder::operator=(CTest::propclass_defEncoder&&)
 struct propclass_##NAME {                                                
        ^
main.cpp:58:5: note: in expansion of macro 'CLI_DECLARE_PROPERTY_RW'
     CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
     ^
main.cpp:19:8: note:   no known conversion for argument 1 from 'SomeInterface*' to 'CTest::propclass_defEncoder&&'
 struct propclass_##NAME {                                                
        ^
main.cpp:58:5: note: in expansion of macro 'CLI_DECLARE_PROPERTY_RW'
     CLI_DECLARE_PROPERTY_RW(CTest, SomeInterface*, defEncoder );
     ^
main.cpp: At global scope:
main.cpp:64:14: warning: unused parameter 'argc' [-Wunused-parameter]
 int main(int argc, char* argv[])
              ^
main.cpp:64:31: warning: unused parameter 'argv' [-Wunused-parameter]
 int main(int argc, char* argv[])
                           ^

所以首先要检查的是:寻找operator=时使用的类型是否合理?

no match for 'operator=' (operand types are 'CTest::propclass_defEncoder'
and 'SomeInterface*')

目前看起来不错。然后g++列出它考虑过的所有候选函数。你期待的那个在单子上吗?是的:

note: void CTest::propclass_defEncoder::operator=(const SomeInterface*&)

然后紧接着是

note:    no known conversion for argument 1 from 'SomeInterface*'
         to 'const SomeInterface*&'

啊哈。因为您使用的是预处理器,所以const TYPE&不是对const TYPE的引用。它只是把const标记放在前面,给出const SomeInterface*&,这是对非const指针(指向const数据)的引用。但是,由于输入的SomeInterface*参数不指向const数据,因此不能将该类型的引用绑定到它。

您可能想让operator=具有参数类型SomeInterface* const&。您可以通过在宏中放置TYPE const&而不是const TYPE&来实现这一点,至少在本场景中是这样。但是为了更安全一点,您可以使用typedef并使用c++的实际类型语义:

#define CLI_DECLARE_PROPERTY_RW(OWNERNAME, TYPE, NAME)                   
struct propclass_##NAME {                                                
    typedef TYPE property_type;                                          
    DWORD dummy;                                                         
    /*propclass_##NAME() : dummy() {}*/                                      
    inline operator property_type() {                                    
        return CLI_CONTAINING_RECORD(this, OWNERNAME, NAME)-> get_##NAME ();    
    }                                                                    
    inline void operator=(const property_type &src) {                    
        CLI_CONTAINING_RECORD(this, OWNERNAME, NAME)-> set_##NAME (src); 
    }                                                                    
} NAME;