重载运算符的使用存在歧义

4
下面的代码:
typedef void HELPER;

const HELPER* helper = _helper;

inline ostream& operator <<(ostream& out,  const HELPER* arg) 
{ out << (const char*)(arg); return out; }

如果我尝试进行某些操作,它会崩溃

cout << helper;

具体来说,我得到了以下错误信息:

main.cpp:35:28: 错误:使用重载运算符'<<'不明确 (操作数类型为'basic_ostream>'和'const HELPER *'(即'const void *'))

它列出了几个可能的候选项:

/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/ostream:207:0: note: candidate function
    basic_ostream& operator<<(const void* __p);
                   ^
main.cpp:25:17: note: candidate function
inline ostream& operator <<(ostream& out,  const HELPER* arg) 
                ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/ostream:195:20: note: candidate function
    basic_ostream& operator<<(bool __n);
                   ^

我有些惊讶我的typedef在这里没有引发更强的类型匹配。我该如何运行这个运算符重载?
编辑:进一步澄清,此代码的目的是我正在对一组Arduino库进行双重定位。它们经常使用以下方式管理字符串:
typedef void __FlashStringHelper;

void showHelp(const __FlashStringHelper* helpText)
{
   Serial.print(helpText);
}

我喜欢iostream并计划使用双目标,所以我在Serial对象上重载了<<,并将之前的内容改为(这是简化的版本,仅供参考)

#define cout Serial

void showHelp(const __FlashStringHelper* helpText)
{
   cout << helpText;
}

现在我想要实际针对不同的架构目标真正的iostream,但旧的Arduino代码不能太多地改变其__FlashStringHelpers。这就是我的问题所在。


5
你的符号 HELPER 基本上只是 void 的别名。因此,你有两个重载版本的 const void*(你的和标准的),再加上指针可以隐式转换为 bool,这给了你第三种选择。 - Some programmer dude
5
typedef 并不会引入新的类型。 - Danh
5
你展示的解决方案是为了解决什么实际问题?为什么要这样过载?它的目的是什么?也许我们可以帮助你解决这个问题,而不是使用你展示的方法。请参考有关“XY 问题”的一些相关阅读材料。 - Some programmer dude
感谢大家,现在它已经可以工作了! - Malachi
2个回答

3

typedef 不会创建新类型,而是给已有类型取个别名。

inline ostream& operator <<(ostream& out,  const HELPER* arg) 

等同于

inline ostream& operator <<(ostream& out,  const void* arg)

也许你想创建一个名为 HELPER 的类型。
class HELPER{};

可能还需要提到的是,您不能重载内置类型。 - NathanOliver
operator<<属于哪种类型,OP正在覆盖它?https://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx - Owen Delahoy

0
作为Zekian已经回答了你的问题,这里有一些可能对你有用或者帮助你实现你尝试做的事情的东西。
#include <iostream>

template <class T>
class Helper {
private:
    T obj_;

public:
    explicit Helper<T>( T obj ) : obj_(obj) {}

public:
    T getObj() const { return obj_; }
    void setObj( T obj ) { obj_ = obj; }        

    template<class U>
    inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ); 
};

template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
    return out << rhs.obj_;
}

int main() {
    Helper<int> helper( 3 );
    std::cout << helper << std::endl;
    return 0;
}

这是一个包装类模板,带有重载的ostream运算符<<。它适用于整数和原子类型。如果您传递另一个结构体或类对象,则必须为它们定义其他重载的ostream运算符。

示例 - 相同的类模板,但这次使用类或结构体。

#include <iostream>

template <class T>
class Helper {
private:
    T obj_;

public:
    explicit Helper<T>( T obj ) : obj_(obj) {}

public:
    T getObj() const { return obj_; }
    void setObj( T obj ) { obj_ = obj; }

    template<class U>
    inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ); 
};

template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
    return out << rhs.obj_;
}

struct Staff {
    int employees = 4; // Default to 4
};

int main() {
    Staff staff; 
    Helper<Staff> helper( staff );
    std::cout << helper << std::endl; // will not compile

    return 0;
}

为了解决这个问题,ostream需要一个Staff对象的重载运算符。

template <class T>
class Helper {
private:
    T obj_;

public:
    explicit Helper<T>( T obj ) : obj_(obj) {}

public:
    T getObj() const { return obj_; }
    void setObj( T obj ) { obj_ = obj; }

    template<class U>
    inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs );
};

template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
    return out << rhs.obj_;
}

struct Staff {
    int employees = 4;

    inline friend std::ostream& operator<< ( std::ostream& out, const Staff& rhs );
};

std::ostream& operator<<( std::ostream& out, const Staff& rhs ) {
    return out << rhs.employees;
}

int main() {

    Staff staff;
    Helper<Staff> helper( staff );   // Default to 4
    std::cout << helper << std::endl; // Will Print 4
    // To Change Staff's Employee count for the helper wrapper do this:
    staff.employees = 12; // Change To 12
    helper.setObj( staff ); // pass the changed struct back into helper
    std::cout << helper3 << std::endl; // Will Now Print 12

    // And For Other Default Types
    Helper<int> helper2( 3 );
    std::cout << helper2 << std::endl;

    Helper<float> helper3( 2.4f );
    std::cout << helper3 << std::endl;

    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接