C++ SFINAE: is_constructible for const char[] vs std::string [英] C++ SFINAE : is_constructible for const char[] vs std::string

查看:43
本文介绍了C++ SFINAE: is_constructible for const char[] vs std::string的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试禁用具有非 std::string 可构造类型的构造函数.我的第一次尝试是这样的:

I'm trying to disable ctor that has non-std::string constructible type. My 1st attempt was like this :

#include <iostream>

struct A
{
    template <typename U, typename = typename std::enable_if<std::is_constructible<std::string, U>::value>::type>
    A(U&& val)
    {
        std::cout << "A(std::string&& val)" << std::string(std::forward<U>(val)) << std::endl;
    }

    template <typename U, typename = typename std::enable_if<not std::is_constructible<std::string, U>::value>::type>
    A(U&& val)
    {
        std::cout << "A(int&& val)" << val << std::endl;
    }
};

int main()
{
    A a1(1);
    A a2("hello");
    A a3(std::string("hello"));
}

但是编译失败

A a1(1);

带有以下错误消息:

错误 C2535:'A::A(U &&)':成员函数已经定义或声明 (现场示例).

error C2535: 'A::A(U &&)': member function already defined or declared (live example).

这意味着,SFINAE 的两个条件都成功了,并且两个ctors 都被使用了.

That means, that both conditions for SFINAE succeeded and both ctors are used.

我继续尝试以下方法:

#include <iostream>

struct A
{
    template <typename U>
    A(U&& val, typename std::enable_if<std::is_constructible<std::string, U>::value>::type* = nullptr)
    {
        std::cout << "A(std::string&& val)" << std::string(std::forward<U>(val)) << std::endl;
    }

    template <typename U>
    A(U&& val, typename std::enable_if<not std::is_constructible<std::string, U>::value>::type* = nullptr)
    {
        std::cout << "A(int&& val)" << val << std::endl;
    }
};

int main()
{
    A a1(1);
    A a2("hello");
    A a3(std::string("hello"));
}

幸运的是,它编译并运行良好(现场示例).

Luckily it compiles and works fine (live example).

到目前为止,我对第二个解决方案还算满意,但我真的不明白为什么使用模板化参数启用/禁用 ctor 的第一种方法不起作用.

So far, Im pretty fine with the 2nd solution but I don't really understand why the 1st approach with enabling/disabling ctor using templated parameter doesn't work.

推荐答案

条件不全,那是不可能的.您可以确信第二种方法是有效的,如果两种方法仍然正确,这种情况就不会发生.

The conditions are not both true, that would be impossible. You can be assured of it by the fact the second approach works, which would not happen if both were still true.

要记住的重要一点是默认模板参数不是函数模板签名的一部分.如果我们稍微减少两个 c'tor 到他们的签名,我们会得到这个:

What's important to remember is that default template arguments are not part of the function template's signature. If we somewhat reduce the two c'tors down to their signatures, we'll get this:

template <typename U, typename>
A(U&& val)
{
}

template <typename U, typename>
A(U&& val)
{
}

两者完全相同.所以发生的是 U 的模板参数推导,并尝试进行替换以查看选择哪个重载.即使我们无法完成其中一个重载的模板参数推导(最后一个参数在其中一个中总是下落不明),我们仍然可以在尝试推导过程时找到两个具有相同签名的模板.所以程序变得格式错误.

And the two are identical. So what happens is template argument deduction for U and an attempt to do substitution to see which overload to pick. Even though we can't complete template argument deduction for one of the overloads (the last argument is always unaccounted for in one of them), we still have two templates with identical signatures being found when attempting the deduction process. So the program becomes ill-formed.

第二种方法有效,因为签名本身取决于正在评估的 enable_if.这就是为什么这两个重载中的一个总是会被悄悄删除,就好像它从来没有存在过一样.

The second approach works because the signature itself depends on the enable_if being evaluated. That's why one of the two overloads will always be silently removed, as though it was never there.

这篇关于C++ SFINAE: is_constructible for const char[] vs std::string的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆