可能在G ++ 6.1.0中回归

时间:2016-05-04 09:55:48

标签: c++ c++11

以下代码

#include <string>
#include <map>
#include <cassert>

    struct       AV {
        explicit AV(std::string const&) {}
    };

#if 1
    static void check_cache_item(
        std::map<std::string, std::string> const& items) // FIXME remove
    {
        assert(!items.empty());
    }
#endif
    static void check_cache_item(
        std::map<std::string, AV> const& items)
    {
        assert(!items.empty());
    }


int main()
{
    check_cache_item({ { "id", "0" }, { "pk", "#0" } });
    check_cache_item({ { "id", "0" }, { "pk", "#1" } });
    check_cache_item({ { "id", AV{"0"} }, { "pk", AV{"#1"} } });
}

被g ++ 4.8.4,g ++ 5.3.0,clang ++ 3.9.0接受;但是g ++ 6.1.0给出了一个错误:

cci.cc: In function ‘int main()’:
cci.cc:25:55: error: call of overloaded ‘check_cache_item(<brace-enclosed initializer list>)’ is ambiguous
     check_cache_item({ { "id", "0" }, { "pk", "#0" } });
                                                       ^
cci.cc:10:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&)
     static void check_cache_item(
                 ^~~~~~~~~~~~~~~~
cci.cc:16:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, AV>&)
     static void check_cache_item(
                 ^~~~~~~~~~~~~~~~
cci.cc:26:55: error: call of overloaded ‘check_cache_item(<brace-enclosed initializer list>)’ is ambiguous
     check_cache_item({ { "id", "0" }, { "pk", "#1" } });
                                                       ^
cci.cc:10:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&)
     static void check_cache_item(
                 ^~~~~~~~~~~~~~~~
cci.cc:16:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, AV>&)
     static void check_cache_item(
                 ^~~~~~~~~~~~~~~~
cci.cc: At global scope:
cci.cc:10:17: warning: ‘void check_cache_item(const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&)’ defined but not used [-Wunused-function]
     static void check_cache_item(
                 ^~~~~~~~~~~~~~~~

如果我#ifdef第一个构造函数,那么每个编译器都会抛出一个错误(正确的,因为AV构造函数是显式的)。

这是G ++ 6.1.0中的回归吗?

1 个答案:

答案 0 :(得分:14)

这是标准的一个令人惊讶且有些不幸的方面(我甚至称之为缺陷);它是复制列表初始化的重载决策规则(CWG 1228中确认的 [over.match.list] )与元素转发构造函数之间发生冲突的结果。 import UIKit class CustomCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate { @IBOutlet weak var answer: UITextField! var delegate: QuestionSelectorCellDelegate? var pickOption: [String] = [] var pickerView:UIPickerView = UIPickerView() override func awakeFromNib() { super.awakeFromNib() // Initialization code } @IBAction func editBeginQuestionSelectorCell(sender: UITextField) { pickerView = UIPickerView() pickerView.delegate = self sender.inputView = pickerView } func displayBlock(block: Block){ if block.answers != nil { pickOption = block.answers! // block.answers! = ["blue","red","green"] for example } } func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { return 1 } func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return pickOption.count } func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return pickOption[row] } func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { if row < pickOption.count { answer.text = pickOption[row] delegate?.updateQuestionSelectorCell(self, rep: pickOption[row]) } } } (根据n4387)。

gcc(&gt; = 6.1.0)拒绝你的程序是正确的; clang接受它是不正确的。早期版本的gcc接受你的程序,因为他们还没有实现n4387; clang接受您的计划,因为它excludes explicit constructors from consideration for overload resolution for copy-list-initialization,根据标准(Calling an explicit constructor with a braced-init list: ambiguous or not?)违反 [over.match.list]

如果我们剥离程序中无关紧要的方面,那就归结为一个简单的重载决策问题:

pair

此处struct A { explicit A(int, int); }; struct B { B(int, int); }; void f(A); void f(B); int main() { f({0, 0}); } 代表Apair<std::string const, AV>代表Bpair<string const, string>的构造函数是显式的,因为它涉及A的显式构造函数n4387;但根据CWG 1228,复制列表初始化的规则:

  

[...]包括所有构造函数,但声明如果通过重载决策选择了显式构造函数,程序就会形成错误。 [...]

[over.match.list]

  

[...]在复制列表初始化中,如果选择了AV构造函数,则初始化是错误的。 [注意:这与其他情况([over.match.ctor],[over.match.copy])不同,其中只考虑转换构造函数进行复制初始化。此限制仅适用于此初始化是重载解析的最终结果的一部分。 - 结束记录]

因此,您的程序被正确考虑(在目前的标准下)是不明确的。

进一步阅读:What could go wrong if copy-list-initialization allowed explicit constructors?