为何选择"<<"运算符作为一个函数导致"模糊调用"编译错误?

时间:2018-05-15 10:18:20

标签: c++

为什么第一个代码段工作正常,但第二个会导致一个模糊的调用错误?为什么编译器在第二种情况下不能解决函数重载?

摘录1:

int main() {
    int x = 1234;
    std::cout << x;
}

摘录2:

int main() {
    int x = 1234;
    operator<<(std::cout, x);
}

编译错误

  

&#34;运算符&lt;&lt;&##;匹配参数列表

     

std :: operator&lt;&lt;&#39;:对重载函数的模糊调用

4 个答案:

答案 0 :(得分:4)

您正在尝试调用成员函数(std::cout),就像它是一个自由函数一样:http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt

歧义可能来自多重匹配,这些匹配都涉及某种转换,其中没有一种是优选的。编译器错误可能会给你一些可怕的不可读的可能匹配列表,所有这些似乎都无关紧要?

对于运营商,将其称为运营商,而不是功能!将运算符定义为成员是有充分理由的,并且有充分的理由将它们定义为自由函数。您不应该关心在任何特定情况下使用哪种。

如果我想创建支持+的我自己的类型,我可能有很好的技术理由选择一种方法而不是另一种方法,甚至在未来版本的库中改变主意。你应该关心我选择哪个吗?

请注意operator<<是内置类型的成员函数(即int s的各种风格),但对于其他类型是非成员函数,例如{{3} }或char const*

答案 1 :(得分:3)

因为整数没有全局(或非成员)operator<< overloaded function。它是a member of the output stream

std::cout.operator<<(x);

一个好的编译器应该向你展示一个模糊调用的可能替代方案,它应该告诉你这个。

答案 2 :(得分:1)

运算符是非静态成员函数,因此您可以使用 来自:how to call an operator as function in C++

#include <iostream>

int main() {
    int x = 1234;
    std::cout.operator<<(x);
}

答案 3 :(得分:0)

来自here

x

如果重载决策无法选择与此类不同功能相比唯一更好的调用匹配,则调用将不明确。对于char(int),signed char版本和#include <iostream> void foo(char a) { } void foo(signed char b) { } int main() { foo(1); } 版本都适合,因此它将是不明确的。还有一个例子:

template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& const char* s );
  

prog.cc:在函数&#39; int main()&#39;:   prog.cc:11:10:错误:调用重载&#39; foo(int)&#39;很暧昧        FOO(1);

  

但是这段代码运行良好的运算符&lt;&lt;(std :: cout,&#34; hello&#34;);

因为

operator<<(std::cout, "hello");

const char* z = "char*"; // OK const signed char* x = "signed char*"; // invalid conversion from ‘const char*’ to ‘const signed char*’ const unsigned char y = "unsigned char*"; // invalid conversion from ‘const char*’ to ‘unsigned char’ 的唯一选择。还有一个例子:

<DataGrid
        IsReadOnly="False"
        ItemsSource="{Binding Path=Items, Mode=OneWay}">
        <DataGrid.Columns>
            <DataGridTemplateColumn
                Header="Test"
                IsReadOnly="False"
                Width="70">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock
                            VerticalAlignment="Center"
                            TextAlignment="Left"
                            Text="{Binding Path=Id, Mode=OneWay}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox
                            Name="cmbTest"
                            DisplayMemberPath=""
                            HorizontalAlignment="Stretch"
                            IsEditable="True"
                            IsEnabled="True"
                            IsReadOnly="False"
                            IsSynchronizedWithCurrentItem="False"
                            ItemsSource="{Binding Path=Items2, Mode=OneWay}"
                            Margin="0"
                            SelectedItem="{x:Null}"
                            SelectedValue="{x:Null}"
                            SelectedValuePath=""
                            Text=""
                            VerticalAlignment="Center"
                            Visibility="Visible"
                            SelectionChanged="cmbTest_SelectionChanged">
                        </ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>