【问题标题】:Make a template type be more specific (T => Certain<X>) to help content-assist使模板类型更具体(T => 确定<X>)以帮助内容辅助
【发布时间】:2017-10-17 21:15:21
【问题描述】:

如何使模板类型在内部更具体以帮助内容辅助?

template<class T>class B{  //note: in real case, it has more template parameter
    public: void f(){}
};
template<class B1>class C{ //<-- I know for sure that B1 derived from "B<something>".    
    B1* b;
    void test(){
        b->
             ^ ctrl+space doesn't show f()
    }
};

我糟糕的解决方法是在 C 类中创建模板专业化,但它会以另一种方式混淆内容辅助。

下面是另一种解决方法,但它很乏味。
我必须在B 反映模板参数,并在C 一个接一个地使用这样的反映。

template<class T>class B{  
    public: using reflectiveT=T;
    /* other T e.g. reflectiveT2=T2 , ... */
    public: void f(){}
};
template<class B1>class C{ 
    using BX=B<B1::reflectiveT>; //B<B1::reflectiveT1,..T2,...T3> ... tedious
    BX* b;
    void test(){
        b->
             ^ ctrl+space will show f()
    }
};

问题:

  • 它遭受可维护性问题, 当我想重构 B 以便以后有更多/更少的模板参数时。
  • 如果BX 恰好是从B&lt;something&gt;派生的类,BXT 将 != BX

我的梦想是:

template<class B1>class C{ 
    using BX=B<...> as base of B1;   //????
};

我可能也依赖内容辅助,但它极大地帮助我编写非常复杂的类。

编辑

我不能只在 B 中传递 Args 作为 C 的模板参数,因为 C 可能会出错。

例如,B&lt;D&gt;::callback 将被调用而不是下面代码中的D::callback (demo):-

class x{};
template<class T>class B{
    public: static void callback(){ std::cout<<"B<D>::callback()";       }
};
class D : public B<D>{ //
    public: static void callback(){ std::cout<<"D::callback()"; }
};
template<class... Args>class C{ 
    using BX=B<Args...>;
    BX* b;
    public: void test(){
        BX::callback(); 
        //^ will invoke B<D>::callback (wrong)
        //  instead of D::callback
    }
};
int main(){
    C<D> c;  c.test();  //print "B<D>::callback()"
}

编辑:大大简化问题。

【问题讨论】:

  • 如果您说的是 Intellisense,我不确定这是否是一项功能。
  • @Gill Bates 是的,我说的是 Intellisense 或任何可以在 Visual-Studio 中帮助我的插件(reshaper/visual-assist)。我编辑了标签,谢谢。
  • 即使BTXB&lt;..&gt;btx-&gt; 也没有必要的f()(因为专业化)。
  • @Jarod42 ... 至少,让它只在没有专业化的情况下工作......或者总是显示f(),即使在某些专业化中没有这样的功能...... . 我更喜欢说话太多而不是沉默的内容辅助。
  • 你有什么理由不想在B 类的参数上创建类C 模板?例如。 template &lt;typename... Args&gt; class C { using BXT = B&lt;Args...&gt;; }.

标签: c++ visual-studio templates c++14 intellisense


【解决方案1】:

您可以将每个函数的实现和接口分开:

#include <iostream>

// Base class with default implementations and common interface
template<class T> class B {
    static void callback_impl() { std::cout<<"B<T>::callback()\n"; }
    void f_impl() { std::cout << "B<T>::f()\n"; }
public:
    static void callback() { T::callback_impl(); }
    void f() { static_cast<T*>(this)->f_impl(); }
};

class D1 : public B<D1>{ // D1 overrides callback
    friend class B<D1>;
    static void callback_impl(){ std::cout<<"D1::callback()\n"; }
};
class D2 : public B<D2> { // D2 overrides f
    friend class B<D2>;
    void f_impl() { std::cout << "D2::f()\n"; }
};

template<class... Args>class C{
    using BX=B<Args...>;
    BX b;
    public: void test(){
        BX::callback();
        b.f();
    }
};

int main(){
    C<D1> c1;  c1.test();  //print "D1::callback()\nB<T>::f()\n"
    C<D2> c2;  c2.test();  //print "B<T>::callback()\nD2::f()\n"
}

【讨论】:

  • 创意间接,谢谢。我相信这个答案很难被击败。虽然它解决了大部分问题(现在它支持派生),但我仍然必须使用手动反射,对吗?
  • 查看这个问题,了解为什么 C++ 不支持反射(默认情况下):stackoverflow.com/questions/359237/…。您可以将B 的所有方法设为虚拟(无需对其进行模板化)——但这通常会导致运行时性能变差。例如,您不能再在 C 中按值存储 b
  • 哦,我其实很喜欢 C++ 不支持反射这一事实。我只想检查我是否正确理解了基本问题和回答内容。我什至不确定“反思”这个词在这里是否合适。
  • 我想我不明白您所说的“手动反射”是什么意思。您当然可以像原来一样保留您的代码(缺点是您的 IDE 无法分辨 B1 有哪些方法)。你想要像 Java 的 class C&lt;B1 extends B&lt;?&gt; &gt; 这样的东西吗(抱歉,如果 Java 语法无效,我已经用了一段时间了)?有一些尝试将Concepts 引入 C++
  • Op,对不起,我重新阅读了您的答案,我开始觉得您的解决方案可以解决这两个问题。它使我在此处发表的评论中的所有论点/怀疑都无效。 XD
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-05
  • 1970-01-01
  • 2019-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多