SFINAE 构造函数中存在 `is_constructible` 问题

问题描述 投票:0回答:1

我无法理解为什么以下代码无法编译:

#include <iostream>
#include <vector>
#include <type_traits>

enum class Error
{
    OK = 0,
    NOK = 1
};

template <typename T, typename E = Error>
class Foo
{
public:
    template <typename U = T,
              std::enable_if_t<std::is_constructible<U>::value, bool> = true>
    Foo(U&& other)
    {
        new (&value_) T(std::forward<U>(other));
    }

private:
    union
    {
        T value_;
        E error_;
    };
};

// usage:
Foo<std::int32_t> Check(std::vector<std::int32_t>& data)
{
    // some code...
    return data.at(0); // here is the problem 
}

int main()
{
    std::vector<std::int32_t> data{1, 2};
    auto res = Check(data);
    return 0;
}

并产生错误:

could not convert ‘(& data)->std::vector::at(0)’ from ‘__gnu_cxx::__alloc_traits, int>::value_type’ {aka ‘int’} to ‘Foo’

这是代码:https://onecompiler.com/cpp/42n6d9sj8

虽然只是改变这个:

std::enable_if_t<std::is_constructible<U>::value, bool> = true>

到此

std::enable_if_t<std::is_constructible<T, U>::value, bool> = true>

修复它。

我的理解: 我返回

data.at(0)
,这将是
int32_t
所以
U = int32_t
。在
std::is_constructible<U>
中,将检查
int32_t
是否可构造(true)。因此应该启用构造函数并创建 Foo 的实例......

第二个版本

std::enable_if_t<std::is_constructible<T, U>::value, bool> = true>

我检查

T
是否可以从
U
构造,两者都是
int32_t
类型,所以我检查
int32_t
是否可以从
int32_t
构造并且它通过了,因为它是真的,因为
U
是相同的如
T
。我不认为这会是一个真正的修复,但我不知道在这种情况下正确的代码应该是什么样子......

c++ c++14 sfinae type-traits
1个回答
0
投票

问题是您使用的是转发引用,这意味着

U
被推导为
std::int32_t&
而不是
std::int32_t

所以

std::is_constructible<U>::value
失败,因为
U
std::int32_t&
。您可以通过从函数参数中删除
&&
来验证这一点。

无转发参考的演示

© www.soinside.com 2019 - 2024. All rights reserved.