当前位置: 首页 > 知识库问答 >
问题:

C 17 if constexpr()与元组一起使用

池永长
2023-03-14

我使用的是启用了C 17支持的VS2017。

我想尝试创建一个“Transformer”类,当提供受支持的某种类型时,它将转换该类型,否则它将按原样返回变量。目标是将所有变量类型传递给转换器,并“隐藏”其转换的变量类型。这样,调用方可以尝试转换所有内容,而不必担心是否需要转换,转换器就会知道。

一个更完整的示例(从原文编辑):

    class MyPoint
{
public:
    int x = 0;
};

class NotMyPoint
{
public:
    int x = 50;
};

template <typename T>
class ITransform
{
    public:

    virtual ~ITransform() {};

    virtual T InTransform(const T &in) const = 0;

    virtual T OutTransform(const T &out) const = 0;

    //Check if the argument type is the same as this class type
    template <typename X>
    constexpr bool CanTransform() const
    {
        return std::is_same<X, T>::value;
    }
};

class MyTransformer :
    public ITransform<MyPoint>
{
public:
    MyTransformer() = default;

    virtual MyPoint InTransform(const MyPoint &in) const override
    {
        auto newPt = in;
        newPt.x += 100;
        return newPt;
    }

    virtual MyPoint OutTransform(const MyPoint &in) const override
    {
        auto newPt = in;
        newPt.x -= 100;
        return newPt;
    }
};

template <class... TRANSFORMERS>
struct VariadicTransformer
{
    constexpr VariadicTransformer() = default;

    /** \brief parse using validateParse but catch throw */
    template <typename T>
    inline T Transform(const T& in)
    {
        return TransformImpl<sizeof...(TRANSFORMERS)-1, T>(in);
    }

private:
    /// last attempt to find matching transformer at I==0, if it fails return the original value
    template<std::size_t I = 0, typename T>
    inline typename std::enable_if<I == 0, T>::type TransformImpl(const T &in) const
    {
        if (std::get<I>(transformers).CanTransform<T>())
            return std::get<I>(transformers).InTransform(in);
        else
            return in;
    }

    /// attempt to find transformer for this type
    template<std::size_t I = 0, typename T>
    inline typename std::enable_if < I != 0, T>::type TransformImpl(const T &in) const
    {
        if (std::get<I>(transformers).CanTransform<T>())
            return std::get<I>(transformers).InTransform(in);
        else
            return TransformImpl<I - 1, T>(in);
    }

    std::tuple<const TRANSFORMERS...> transformers;
};


//Example usage

VariadicTransformer<MyTransformer, MyTransformer> varTrans;
MyPoint myPoint;
NotMyPoint notMyPoint;

std::cout << myPoint.x << std::endl;
myPoint = varTrans.Transform(myPoint);
std::cout << myPoint.x << std::endl;

std::cout << notMyPoint.x << std::endl;
notMyPoint = varTrans.Transform<NotMyPoint>(notMyPoint);
std::cout << notMyPoint.x << std::endl;

return 0;

我的问题来自这一行:

if constexpr(std::get<I>(transformers).CanTransform<T>())

这将不会编译并提供以下错误:

错误C2131:表达式未计算为常量

注意:失败是由于在变量的生命周期之外读取了变量导致的

注意:请参阅“此”的用法

CanTransform 函数应该是一个 constexpr, std::get

此外,如果Constexr是必需的,以避免试图调用任何不符合转换当前类型的变压器,我希望这个案例失败并返回原始。

关于导致此错误的原因或我可以尝试的其他设计的任何建议?

共有2个答案

夏侯彬郁
2023-03-14

所以我无法解释为什么前一个选项不起作用。然而,通过将CanTransform函数转换为自己的独立函数,错误消失了。

这终于奏效了:

template<typename X, typename T>
constexpr inline bool CanTransform()
{
    return std::is_base_of<ITransform<T>, X>::value;
}

template <class... TRANSFORMERS>
struct VariadicTransformer
{
    constexpr VariadicTransformer() = default;

    template <typename T>
    constexpr inline T Transform(const T& in) const
    {
        return TransformImpl<sizeof...(TRANSFORMERS)-1, T>(in);
    }

private:
        // last attempt to find matching transformer at I==0, if it fails return the original value
    template<std::size_t I = 0, typename T>
    constexpr inline typename std::enable_if<I == 0, T>::type TransformImpl(const T &in) const
    {
        if constexpr(CanTransform < std::tuple_element < I, std::tuple<TRANSFORMERS...>>::type, T >())
            return std::get<I>(transformers).InTransform(in);
        else
            return in;
    }

       // attempt to find transformer for this type
    template<std::size_t I = 0, typename T>
    constexpr inline typename std::enable_if < I != 0, T>::type TransformImpl(const T &in) const
    {
        if constexpr(CanTransform < std::tuple_element < I, std::tuple<TRANSFORMERS...>>::type, T >())
            return std::get<I>(transformers).InTransform(in);
        else
            return TransformImpl<I - 1, T>(in);
    }

    std::tuple<TRANSFORMERS...> transformers;
};
王凌
2023-03-14

只有当调用对象也是的时候,对对象的方法调用才会是的,如果调用对象不是的,那么该方法仍将在运行时而不是编译时进行评估,因此没有资格进行任何编译时评估。

struct A {
    int val;
    constexpr A() : A(16) {}
    constexpr A(int val) : val(val) {}
    constexpr bool foo() const {return val > 15;}
};

int main() {
    A a;
    if constexpr(a.foo()) {
        std::cout << "No point thinking about it; this won't compile!" << std::endl;
    } else {
        std::cout << "Again, the previous line doesn't compile." << std::endl;
    }

    constexpr A b;
    if constexpr(b.foo()) {
        std::cout << "This, however, will compile, and this message will be displayed!" << std::endl;
    }

    constexpr A c(13);
    if constexpr(c.foo()) {
        std::cout << "This will not be displayed because the function will evaluate to false, but it will compile!" << std::endl;
    }
}

您需要确保< code>TransformImpl可以成为< code>constexpr,然后确保调用< code>TransformImpl的< code>A的实例也是< code>constexpr。

 类似资料:
  • 问题内容: 我的项目遇到了麻烦。谁能向我解释为什么我不能使用来访问? 下面是我的切入点的代码: 我正在尝试使用该方法访问“ 菜单” 组件中的设置。请参阅下面的 菜单 : 我真的很想知道为什么我可以使用来访问和值。我已经阅读了文档并寻找了其他资源,但是我还没有答案,但是我希望有办法可以做到。 问题答案: method中的第一个参数是包含任何属性和方法的对象,它不引用存在属性的React组件。 如果您

  • 问题内容: 使用,为什么它对(原始类型)和数组显示不同的列表大小? a)对于数组,每当我执行以下程序时,列表大小= 1 b)但是,如果我从数组类型更改为array(如),则列表大小为4,我认为这是正确的。 PS :使用(包装类)数组,则结果很好,但是我不确定为什么在原始数组中列表大小为1。请解释。 问题答案: 由于Java泛型而无法保存原始值(请参阅类似的问题)。因此,当您调用Arrays 时,将

  • 问题内容: 我在该领域做了一些谷歌搜索,发现了很多有关让Jenkins理解boost.test的XML输出格式的讨论,但是没有规范的参考。 有人说我们只需要使用XLST来转换XML格式,另一些人则认为XML在此之前需要进行一些修改有人拥有XSL来将Boost.TestXML日志转换为可显示的格式吗?)。有些人建议xUnit插件可以原生理解boost.test XML格式,另一些人则认为它不能 因为

  • 我有一个烧瓶服务器运行在http://127.0.0.1:5000和一个vuejs前端运行http://localhost:8080我已经做了api,并用postman测试了它,一切都如预期的那样工作:( > 将请求发布到/登录- (将请求发送至/登录)- 烧瓶API代码: 登录。vue: 指数vue 当我使用邮递员登录时,我得到的响应为;当我使用邮递员获取url/索引时,我得到响应。数据但当我使

  • 问题内容: UPDATE 3 下面的最终工作代码。您需要src文件夹中的ace.js!从库中无法使用,您需要从其站点下载预包装的版本。 上面的代码可以设置ACE窗口的内容。 更新2 这是我的项目看起来像atm的样子,仍然在右上角显示了白色的屏幕,并带有来自WT的红色“正在加载…”消息。下面有更多注释。 当用于编辑器-> doJavaScript(command)时,“ command”变量等于以下

  • 问题内容: 我正在使用PDO来执行一条语句,该语句使用将数组作为其值的子句: 上面的代码工作得很好,但是我的问题是为什么不能: 此代码将返回等于(1)中第一项的项目,但不返回数组(2和3)中的其余项目。 问题答案: PDO不适用于此类情况。您需要动态创建带有问号的字符串并将其插入查询中。 如果查询中还有其他占位符,则可以使用以下方法(代码取自我的PDO教程): 您可以使用函数将所有变量连接到单个数