【问题标题】:Conditional member signature and implementation based on template type parameter基于模板类型参数的条件成员签名及实现
【发布时间】:2017-09-26 12:07:18
【问题描述】:

我正在尝试编写具有多个类型参数T1T2 的模板类。该类有一个类型为std::promise<T2> 的私​​有成员。

template <class T, class T2>
class Test
{
public:
    void setValue(T2 value)
    {
        promise.set_value(value);
    }

    void setValue()
    {
        promise.set_value();
    }

private:
    std::promise<T2> promise;
};

T2 不是 void 时,这个类编译得很好(只要你不调用没有参数的setValue。当T2 是 void 时,我得到一个编译器错误:

error C2182: 'value' : illegal use of type 'void'

T2 不为空时,我想使用第一个setValue 方法,它有一个T2 类型的参数。当T2 无效时,我想使用第二个setValue 方法,它不带参数。我看过很多例子,但我对模板编程比较陌生,我似乎无法让它工作。

是否有可能用 std::enable_if 以某种方式完成此任务?还是使用模板专业化?

【问题讨论】:

    标签: c++


    【解决方案1】:

    帮助模板类专业化:

    #include <future>
    
    template<typename T>
    class TestHelper
    {
    public:
        void setValue(T const& v)
        { promise.set_value(v); }
    
    private:
        std::promise<T> promise;
    };
    
    template<>
    class TestHelper<void>
    {
    public:
        void setValue()
        { promise.set_value(); }
    
    private:
        std::promise<void> promise;
    };
    
    template <class T, class T2>
    class Test : public TestHelper<T2>
    {
    };
    
    int main()
    {
        Test<void, int> t;
        // t.setValue(); // compilation error: no matching function for call to 'std::promise<int>::set_value()'
        t.setValue(0);
    
        Test<void, void> t1;
        t1.setValue();
        // t1.setValue(0); // compilation error: no matching function for call to 'std::promise<void>::set_value(int)'
    }
    

    【讨论】:

    • 复制我的答案。 ;)
    • 谢谢,解决了!但是,我有另一种访问promise 的方法,Test 无法访问该方法。我应该把所说的方法放在哪里?我当然可以对其进行保护,但我只是想知道是否可以采取不同的方式。
    • @jkokorian:在这种情况下,最好将promise 移至基类并使其像@ypnos 答案中那样受到保护(或添加受保护的getter 方法)
    【解决方案2】:

    你可以通过对基类的条件依赖来解决这个问题:

    #include <future>
    #include <type_traits>
    #include <iostream>
    
    template<class T2>
    struct Base {
    protected:
        std::promise<T2> promise;
    };
    
    template<class T2>
    struct BaseWithVariable : public Base<T2> {
        void setValue(T2 value)
        {
            this->promise.set_value(value);
        }
    };
    
    template<typename T2>
    struct BaseWithoutVariable : public Base<T2> {
        void setValue()
        {
            this->promise.set_value();
        }
    };
    
    template<typename T, typename T2>
    class Test
    : public std::conditional<std::is_same_v<T2, void>, BaseWithoutVariable<T2>, BaseWithVariable<T2>>::type
    {
    };
    
    int main()
    {
        Test<int, int> a;
        a.setValue(5);
        Test<int, void> b;
        b.setValue();
    }
    

    现在你意识到你可以通过中级级别的专业化来达到同样的效果:

    template<class T2>
    struct BaseSetter : public Base<T2> {
        void setValue(T2 value)
        {
            this->promise.set_value(value);
        }
    };
    
    template<>
    struct BaseSetter<void> : public Base<void> {
        void setValue()
        {
            this->promise.set_value();
        }
    };
    
    template<typename T, typename T2>
    class Test : public BaseSetter<T2>
    {
    };
    

    在这种特殊情况下,省略Base 的使用并让BaseSetter 的两个变体分别使用它们自己的成员变量std::promise&lt;T2&gt;std::promise&lt;void&gt; 也没有什么坏处。

    但是,所有这些在 GCC 7.2.0 运行时都会崩溃。我不知道为什么。

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 2017-10-18
      • 1970-01-01
      • 2014-06-17
      • 1970-01-01
      • 2017-04-02
      相关资源
      最近更新 更多