【问题标题】:How to avoid redefinition of typedefs in template class?如何避免在模板类中重新定义 typedef?
【发布时间】:2020-10-11 19:46:59
【问题描述】:

我正在尝试创建一个获取和设置的类,具体取决于它是否传递了 getter 和 setter,或者只是一个指向要获取和设置的变量的指针。这个想法是,当它使用指针参数构造时, TGetter 和 TSetter 成员只是默认为 chars 并且不做任何事情。如果使用 setter 和 getter 构造函数调用它,则指向变量的指针默认为 char 并且不执行任何操作。我尝试使用带有 typedefs 的 std::enable_if 来确定 T 是什么,但我得到了多个定义:

template <typename TGetter = char, typename TSetter = char, typename Tptr = char> 
struct GetterSetter  
    // IF THE PTR CONSTRUCTOR IS CALLED THEN I WANT T TO BE THE TYPE OF TGetter() called result.
    // IF THE GETTER AND SETTER CONSTRUCTOR IS CALLED I WANT T TO BE THE TYPE OF
    // T DEREFERENCED
{
    typedef std::enable_if<std::is_same_v<Tptr, char>, std::invoke_result_t<TGetter>> T;
    typedef std::enable_if < std::is_same_v<TGetter, char>, std::remove_pointer_t<Tptr>> T;
    

    GetterSetter(TGetter getter, TSetter setter) : getter(getter), setter(setter) {}
    GetterSetter(Tptr ptr) : ptrToT(ptr) {}

    TGetter getter;
    TSetter setter;
    Tptr ptrToT;

    T get()
    {
        if constexpr (std::is_same_v<Tptr, char>) return *ptrToT;
        else return getter();
    }

    void set(T t)
    {
        if constexpr (std::is_same_v<Tptr, char>) *ptrToT = t;
        else setter(t);
    }
};

如何预防?我根本没有实例化这个类,我得到了重新定义编译器错误。

【问题讨论】:

  • std::enable_if-base 将 SFINAE 与函数重载解析一起使用。没有 typedef 的重载决议之类的东西。仅适用于函数和类。
  • 你不能根据你如何构造一个类的object来选择一个类成员。 T 是该类的成员。它独立于任何对象而存在。
  • 按照我看到的编写方式,代码总是使用 getter 和 setter,但它的构造函数接受适当类型的指针并创建适当的 lambdas 用作它的 getter 和 setter。这似乎比试图弄乱不同的typedefs 要干净一些。
  • @Nathan Pierson 是的,我认为这在课堂上可能更干净,但是无论何时调用它,GetterSetter(&myvariable);和 GetterSetter( [ ] {return myvariable;}, [] (int i) { myvariable = i;});
  • 您可以仅通过T 对类进行参数化,然后您可以使用std::function&lt;T(void)&gt; getter; 而不是TGetter getter;。您编写一个接受 T* 并生成适当 lambda 的 ctor,然后编写一个直接采用 getter 和 setter 函数的 ctor 重载。调用代码仍然看起来像 getterSetter.get()getterSetter.set(newValue)

标签: c++ typedef


【解决方案1】:

您不能使用std::enable_if 有条件地选择typedefs。为此,您可以编写:

typedef std::conditional_t<std::is_same_v<TGetter, char>,
                           std::remove_pointer_t<Tptr>, 
                           std::invoke_result_t<TGetter>> T;

或者最好:

using T = std::conditional_t<std::is_same_v<TGetter, char>,
                             std::remove_pointer_t<Tptr>, 
                             std::invoke_result_t<TGetter>>;

假设T 必须是这两种类型之一。

【讨论】:

  • 哦,我明白了。如果情况是三个或更多,您是否需要嵌套它们?读起来真的很混乱。
  • 嗯,可能。这可能取决于实际情况。编辑您的问题以要求 3 路选择,我会尝试更新答案。
  • @Zebrafish 当您需要三个或更多时,具有特化的模板别名可能是另一种选择。
  • TGetterchar 更好时需要处理(当前尝试评估std::invoke_result_t&lt;char&gt;)。在这种情况下,typename std::conditional_t&lt;std::is_same_v&lt;TGetter, char&gt;, std::remove_pointer&lt;Tptr&gt;, std::invoke_result&lt;TGetter&gt;&gt;::type 可以工作。
  • @cigien 哦,对。正在考虑模板变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
  • 1970-01-01
  • 1970-01-01
  • 2016-12-21
  • 2014-09-10
  • 2011-11-15
相关资源
最近更新 更多