C++ 对于多个参数,_是可转换的吗

C++ 对于多个参数,_是可转换的吗,c++,c++11,implicit-conversion,sfinae,typetraits,C++,C++11,Implicit Conversion,Sfinae,Typetraits,假设出于任何原因,我没有std::is_convertible,并且希望自己实现它。该标准的表述大致如下: 当且仅当以下代码中的返回表达式格式良好(包括对函数返回类型的任何隐式转换)时,应满足模板专用化的谓词条件是可转换的: To f() { return declval<From>(); } To f() { return {declval<From>()...}; } 这似乎是有意为之,就我所知,它也做了同样的事情 现在我可以区分隐式和显式(或根本

假设出于任何原因,我没有std::is_convertible,并且希望自己实现它。该标准的表述大致如下:

当且仅当以下代码中的返回表达式格式良好(包括对函数返回类型的任何隐式转换)时,应满足模板专用化的谓词条件
是可转换的

To f() {
    return declval<From>();
}
To f() {
    return {declval<From>()...};
}
这似乎是有意为之,就我所知,它也做了同样的事情

现在我可以区分隐式和显式(或根本没有)构造函数:

struct A {};
struct B {};

struct Test {
    Test(A);
    explicit Test(B);
}; 

int main() {   
    std::cout << my_is_convertible<Test, A>::value; // true 
    std::cout << my_is_convertible<Test, B>::value; // false
    return 0;
}
为了实现它,我采取了显而易见的方式:

template <typename To_, typename... From_>
class my_is_convertible_many {
    private:
        template <typename To>
        struct indirector {
            indirector(To);
        };

        template <typename To, typename... From>
        struct tag {};

        template <typename To, typename... From>
        static auto test(tag<To, From...>)
            -> decltype(indirector<To>({std::declval<From>()...}), std::true_type());
        static auto test(...)
            -> std::false_type;

    public:
        static constexpr bool value = decltype(test(tag<To_, From_...>()))::value;
};
错误是关于试图隐式调用显式构造函数,在gcc上听起来像这样:

main.cpp: In substitution of 'template<class To, class ... From> static decltype (((my_is_convertible_many<To_, From_>::indirector<To>)({(declval<From>)()...}), std::true_type())) my_is_convertible_many<To_, From_>::test(my_is_convertible_many<To_, From_>::tag<To, From ...>) [with To = To; From = {From ...}; To_ = Test; From_ = {C, C}] [with To = Test; From = {C, C}]':
main.cpp:21:73:   required from 'constexpr const bool my_is_convertible_many<Test, C, C>::value'
main.cpp:37:54:   required from here
main.cpp:17:97: error: converting to 'Test' from initializer list would use explicit constructor 'Test::Test(C, C)'
         static auto test(tag<To, From...>) -> decltype(indirector<To>({std::declval<From>()...}), std::true_type());
                                                                                                 ^
main.cpp:替换“模板静态decltype(((my_is_convertible_many::indirector)({(declval)(…]),std::true_type())my_is_convertible_many::test(my_is_convertible_many::tag)[with To=To;From={From…};To=test From={C,C}][with To=test From={C,C}]:
main.cpp:21:73:constexpr const bool my_是可转换的\u many::value'中必需的
main.cpp:37:54:此处需要
main.cpp:17:97:错误:从初始值设定项列表转换为“Test”将使用显式构造函数“Test::Test(C,C)”
静态自动测试(tag)->decltype(indirector({std::declval()…}),std::true_type());
^
这是明智的。一、 但是,希望这个
test
重载被忽略,而另一个重载将被使用,因此不会产生错误


所以问题是:为什么不会发生这种情况,我能做些什么呢?

gcc最近刚刚发布,4.9版将接受该代码。clang也接受它,所以代码可能很好。这并不能告诉您如何使用旧版本的GCC来解决这个问题,对不起。

对我来说,这看起来不像<代码> ISTHORITY 。但是<代码> iSuthTeaTyrByx使用< /Calp> > GCC源代码说:“当从init列表转换时,我们考虑显式构造函数,但实际上试图调用一个构造函数是一个错误。”听起来可能是故意的?还是忘了斯芬纳?在任何情况下,修改它的补丁都是微不足道的(cp/call.c中有1或2行)。如果你没有得到一个令人信服的答案,即代码是非法的,请向gcc提交PR。顺便问一下,你有没有检查过其他编译器?@MikeKinghan谢谢,这是一个bug。在gcc-4.9()中修复。下次请别忘了提交一个bug。@Marglisse:也许你应该把它作为一个答案,这样这个问题就可以从未回答的问题列表中删除了?
struct A {};
struct B {};
struct C {};

struct Test {
    Test(A, A);
    //Test(B, B);
    explicit Test(C, C);
}; 

int main() {    
    std::cout << my_is_convertible_many<Test, A, A>::value; // true, correct
    std::cout << my_is_convertible_many<Test, B, B>::value; // false, correct
    std::cout << my_is_convertible_many<Test, C, C>::value; // error
    return 0;
}
main.cpp: In substitution of 'template<class To, class ... From> static decltype (((my_is_convertible_many<To_, From_>::indirector<To>)({(declval<From>)()...}), std::true_type())) my_is_convertible_many<To_, From_>::test(my_is_convertible_many<To_, From_>::tag<To, From ...>) [with To = To; From = {From ...}; To_ = Test; From_ = {C, C}] [with To = Test; From = {C, C}]':
main.cpp:21:73:   required from 'constexpr const bool my_is_convertible_many<Test, C, C>::value'
main.cpp:37:54:   required from here
main.cpp:17:97: error: converting to 'Test' from initializer list would use explicit constructor 'Test::Test(C, C)'
         static auto test(tag<To, From...>) -> decltype(indirector<To>({std::declval<From>()...}), std::true_type());
                                                                                                 ^