SFINAE 用于检查涉及复制赋值的复杂表达式的有效性

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

考虑以下课程并具体注意

Concrete<T>::copy_assign

struct TypeErased
{
    TypeErased() = default;
    TypeErased& operator=(TypeErased const& other) {
        copy_assign(other);
        return *this;
    }
    virtual void copy_assign(TypeErased const& other) = 0;
    virtual ~TypeErased(){}
};

template <typename T>
class Concrete : public TypeErased
{
public:

    template <typename... Args>
    Concrete(Args&&... args) : value(std::forward<Args>(args)...) {}

    T const& get_value() const  {
        return value;
    }

    void copy_assign(TypeErased const& other) override final
    {
        copy_assign_impl(other);
    }

private:

    template <typename U=T>
    void copy_assign_impl(TypeErased const& other) {
        if constexpr (std::is_copy_assignable_v<U>) {
            value = static_cast<Concrete<U> const&>(other).get_value();
        } else {
            throw std::logic_error("Nope!");
        }
    }

    T value;
};

我需要 constexpr-if 才能实例化

Concrete<T>
实例,即使
T
不可复制分配。如果尝试复制分配一个不可复制分配的
Concrete<T>
,我想抛出一个运行时错误。
T

现在我的问题是,if-constexpr 条件并不详尽。我不断遇到这样的情况:条件 
struct NoCopy { NoCopy() = default; NoCopy(NoCopy const&) = delete; NoCopy& operator=(NoCopy const&) = delete; }; int main() { // These work: Concrete<double> x1; // trivial Concrete<std::vector<double>> x2; Concrete<NoCopy> x3; Concrete<std::unique_ptr<double>> x4; Concrete<std::optional<NoCopy>> x5; }

的计算结果为

std::is_copy_assignable_v<T>
,但表达式
true
无效。例如,以下所有实例化都是编译器错误:
value = static_cast<Concrete<T> const&>(other).get_value();

https://godbolt.org/z/6dxh1a7rK

是否有我可以使用的类型特征或某些 SFINAE 魔法,仅使用 C++17 功能来可靠地测试表达式

Concrete<boost::optional<NoCopy>> x6; Concrete<std::vector<NoCopy>> x7; Concrete<std::vector<std::unique_ptr<double>>> x8; Concrete<boost::variant<std::string&, boost::optional<std::string>&>> // I know this is weird, but the types used in Concrete come from external libraries and are not in my hand 的有效性?


注意:当我认为我有问题时,我问了一个类似的问题 

value = static_cast<Concrete<T> const&>(other).get_value();

std::is_copy_assignable 和 boost::Optional 的意外行为

c++ c++17 sfinae type-traits
1个回答
0
投票
我不断遇到这样的情况:条件
boost::optional

的计算结果为 true,但表达式

std::is_copy_assignable_v<T>
无效。例如,以下所有实例化都是编译器错误:
value = static_cast<Concrete<T> const&>(other).get_value();

这里的根本原因是
“SFINAE特殊会员或支持不完整类型:最多选择一个”

(2020-02-05)。 首先,考虑一下你将

永远永远

能够处理这样的邪恶类型: Concrete<boost::optional<NoCopy>> x6; Concrete<std::vector<NoCopy>> x7; Concrete<std::vector<std::unique_ptr<double>>> x8;

此类型
声称

是可复制分配的,但是一旦您尝试实例化其template<class T> struct Evil { Evil& operator=(const Evil&) { static_assert(sizeof(T) == 0); } }; static_assert(std::is_copy_assignable_v<Evil<int>>); 定义,它就会出现硬错误。 (这个错误“不是在直接上下文中”——它不仅仅是替换失败。)

那么你的问题就是“为什么

operator=

表现得像

vector<NoCopy>
?”答案很简单
“SFINAE特殊会员或支持不完整类型:最多选择一个”
Evil<int>必须预先决定是否要
查看并查看
vector是否可复制(在这种情况下,
NoCopy
必须是完整类型,然后你就不能再拥有
NoCopy
了),或者是否会
乐观地假设
它是可复制的(它确实如此;然后你就得到了struct Node { vector<Node> children; }的情况)。
    

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