我无法理解为什么以下代码无法编译:
#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
。我不认为这会是一个真正的修复,但我不知道在这种情况下正确的代码应该是什么样子......
问题是您使用的是转发引用,这意味着
U
被推导为 std::int32_t&
而不是 std::int32_t
。
所以
std::is_constructible<U>::value
失败,因为 U
是 std::int32_t&
。您可以通过从函数参数中删除 &&
来验证这一点。