【问题标题】:std::enable_if to change member *variable* declaration/typestd::enable_if 更改成员 *variable* 声明/类型
【发布时间】:2019-10-18 16:35:55
【问题描述】:

我查看了一些类似的问题,例如 this onethis other one,并且我了解如何使用 enable_if 来处理成员函数

这是一个工作示例:

#include <iostream>

template <int size>
class Test
{
private:
    constexpr static bool ENABLE = (size < 10);

public:
    template <bool E = ENABLE, typename std::enable_if<E, int>::type = 0>
    static int foo();

    template <bool E = ENABLE, typename std::enable_if<!E, int>::type = 0>
    constexpr static int foo();
};

template <int size>
template <bool E, typename std::enable_if<E, int>::type>
int Test<size>::foo()
{
    return 7;
}

template <int size>
template <bool E, typename std::enable_if<!E, int>::type>
constexpr int Test<size>::foo()
{
    return 12;
}

int main()
{
    Test<5> v1;
    Test<15> v2;

    std::cout << v1.foo() << "\n";
    std::cout << v2.foo() << "\n";
}

但是,当我尝试稍微修改代码以适用于成员 变量 时,我得到了令人讨厌的重新声明错误。这甚至可能与变量有关,我只是缺少一些简单的东西吗?

这是我有问题的示例代码:

#include <iostream>

template <int size>
class Test
{
private:
    constexpr static bool ENABLE = (size < 10);

public:
    template <bool E = ENABLE, typename std::enable_if<E, int>::type = 0>
    static int foo;

    template <bool E = ENABLE, typename std::enable_if<!E, int>::type = 0>
    constexpr static int foo = 12;
};

template <int size>
template <bool E, typename std::enable_if<E, int>::type>
int Test<size>::foo = 7;

template <int size>
template <bool E, typename std::enable_if<!E, int>::type>
constexpr int Test<size>::foo;

int main()
{
    Test<5> v1;
    Test<15> v2;

    std::cout << v1.foo<> << "\n";
    std::cout << v2.foo<> << "\n";
}

在此先感谢,感谢任何帮助/指导!

【问题讨论】:

  • 无法通过enable_if控制变量的存在
  • 在此之前,您只能在类级别进行编写以获取变量。尽管这是一个有趣的命题,但在 C++ 20 中通过requires 有条件地包含一个变量。我认为我们不会有任何 ODR 违规,而且会很方便。
  • “替换失败不是错误”(或SFINAE),仅限applies during overload resolution of function templates。显然成员变量不是这种情况......

标签: c++ templates enable-if


【解决方案1】:

您可以通过提供成员foo的条件基类来达到预期的效果:

template<int FOO_INIT>
struct TestImpl1 {
    static int foo;
};

template<int FOO_INIT>
int TestImpl1<FOO_INIT>::foo = FOO_INIT;

template<int FOO_INIT>
struct TestImpl2 {
    constexpr static int foo = FOO_INIT;
};

template<int FOO_INIT>
constexpr int TestImpl2<FOO_INIT>::foo;

template<int size>
struct Test
    : std::conditional<
        (size < 10),
        TestImpl1<7>,
        TestImpl2<12>
      >::type
{};

int main() {
    Test<5> v1;
    Test<15> v2;

    std::cout << v1.foo << "\n";
    std::cout << v2.foo << "\n";

    // constexpr int i1 = v1.foo; // Fails to compile because Test<5>::foo is not constexpr.
    constexpr int i2 = v2.foo; // Compiles because Test<15>::foo is constexpr.
}

【讨论】:

  • 感谢您的回答!我的问题是——如果我想让“测试”在其成员函数中访问/引用 foo 怎么办?
  • @OfekGila this-&gt;foo。或者,using Base = std::conditional_t&lt;(size &lt; 10), TestImpl1&lt;7&gt;, TestImpl2&lt;12&gt;&gt;; 然后Base::foo
【解决方案2】:

如果您只对静态成员变量执行此操作,则仍有机会通过使用块范围的静态变量使它们工作。这样你的foo就变成了一个函数,所以你可以对它们应用SFINAE。

#include <iostream>

template <int size>
class Test
{
private:
    constexpr static bool ENABLE = (size < 10);

public:
    template <bool E = ENABLE, typename std::enable_if<E, int>::type = 0>
    static int& foo();

    template <bool E = ENABLE, typename std::enable_if<!E, int>::type = 0>
    constexpr static int foo();
};

template <int size>
template <bool E, typename std::enable_if<E, int>::type>
int& Test<size>::foo() {
    static int foo_impl = 7;
    return foo_impl;
}

template <int size>
template <bool E, typename std::enable_if<!E, int>::type>
constexpr int Test<size>::foo() {
    return 12;
}

int main()
{
    Test<5> v1;
    Test<15> v2;

    std::cout << v1.foo() << "\n";
    std::cout << v2.foo() << "\n";
}

Live demo

【讨论】:

    猜你喜欢
    • 2020-11-15
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多