C++ 是否有方法提示用户使用哪种数据类型作为模板c++;

C++ 是否有方法提示用户使用哪种数据类型作为模板c++;,c++,pointers,dynamic-programming,C++,Pointers,Dynamic Programming,我正在制作一个带有动态内存和模板的简单双链接列表,它可以接收用户输入来生成它。 现在我想提示用户列表是否由int、float、double或chars组成。有可能吗 template <class T> class le { nodo<T>* head = nullptr; bool (*comp)(T, T); public: le(bool (*c)(T, T) = ascendente) { comp = c; }

我正在制作一个带有动态内存和模板的简单双链接列表,它可以接收用户输入来生成它。 现在我想提示用户列表是否由int、float、double或chars组成。有可能吗

template <class T>
class le
{
    nodo<T>* head = nullptr;
    bool (*comp)(T, T);
public:
    le(bool (*c)(T, T) = ascendente) {
        comp = c;
    }
    void add(T valor);
    void remove(T valor);
    bool find(T bus, nodo<T>*& pos);
    void print();
    ~le();
};
模板
勒班
{
nodo*head=nullptr;
bool(*comp)(T,T);
公众:
乐(布尔(*c)(T,T)=上升){
comp=c;
}
无效添加(T值);
消除空洞(T-valor);
布尔查找(T总线、节点*&pos);
作废打印();
~le();
};
我想到的一个替代方法是为每种数据类型声明4个列表,并为每个列表创建一个指针,但如果有直接的方法,它将节省内存,而且速度会更快

le<int> leInt;
le<char> leChar;
le<float> leInt;
le<double> leChar;
leleint;
勒卡尔;
勒伦特;
勒卡尔;

模板参数必须在编译时计算,而用户输入发生在运行时,因此无法直接根据用户输入指定模板


您将需要在代码中显式指定模板类的多个版本,即作为单独声明的变量、分配公共指针的单独语句、,或者使用其他级别的间接寻址,然后可以根据用户输入进行选择。

处理这一问题最直接的方法是使用适配器,其中适配器都继承自“接口”类型(仅限纯虚拟方法)。为此,您需要知道需要对每个列表执行哪些调整操作

例如,给定单个操作“向列表添加项目”,我们可以使用
std::string
作为参数类型,因为这可能是输入的类型。因此,我们的基本适配器接口如下所示:

class le_adapter {
public:
    virtual ~le_adapter() = default;
    virtual bool add(std::string const &) = 0;
};
现在,我们需要为每种列表类型实现适配器。谢天谢地,模板可以帮助我们:

template <typename T>
class le_adapter_impl : public le_adapter {
public:
    virtual bool add(std::string const &) override;

    le<T> & get();

private:
    le<T> list;
};

template <typename T>
bool le_adapter_impl<T>::add(std::string const & str) {
    // Naive implementation; should do more error checking.
    T value;
    std::istringstream source{str};

    if (source >> value) {
        list.add(value);
        return true;
    }

    return false;
}

template <typename T>
le<T> & le_adapter_impl<T>::get() {
    return list;
}
现在,您有了一个地图,可以根据用户输入的内容来分配适配器:

std::string input{"int"}; // Example user input

auto i = factories.find(input);
if (i != factories.end()) {
    auto adapter = i->second(); // Creates the desired adapter.

    adapter->add("123"); // This would also be user input
} else {
    // Handle invalid selection
}
现在我们有了
adapter
,它是
std::unique\u ptr
。为了使用在基本接口上定义的虚拟方法,您不必知道使用了哪个特定的实现

适配器仅与其基本接口一样有用;如果您需要支持其他操作,那么您必须在该接口上定义它们,并且它们必须具有通用参数或返回值才有用


如果您需要执行广泛的操作/计算,这将受益于了解
T
的类型,那么您可以使用模板函数,并通过重载函子将其应用于适配器。(或者欺骗并在适配器中执行此操作,尽管这可能会被视为违反关注点分离。)

您可以通过编写这样的帮助函数来执行您想要的操作

template <typename T>
void do_work() {
    le<T> list;
    // do stuff
}

int main() {
    if(use_double) {
        do_work<double>();
    }
    else if(use_int) {
        do_work<int>();
    }
}
模板
无效工作{
乐团名单;
//做事
}
int main(){
如果(使用双精度){
你工作吗;
}
else if(使用_int){
你工作吗;
}
}

显然,您需要将
main
中的伪逻辑替换为从用户获取类型所使用的任何逻辑。由于实际逻辑将在
do_work
中,并且您现在有了一个特定的类型(
T
),因此不需要多个
le
实例。这还意味着您可以通过使用新类型调用
do_-work
来添加新类型(例如,
do_-work
,如果您需要int列表。)。

当然可以。更有趣的问题是,您计划如何在不知道其类型的情况下使用此列表?还要注意,您违反了here-因为您有一个析构函数,所以还应该有一个复制和移动构造函数。否则,任何副本都将导致
指针的共享所有权,并最终获得双重自由。处理此问题的最简单方法是将
head
更改为
std::unique_ptr
并删除析构函数,然后确保
nodo
也使用智能指针进行分配。然后销毁和移动是自动的,你可以实现复制。也许你在寻找一个“你需要有多个声明,并根据用户输入选择其中一个。”不完全是这样。还有其他模式也可以工作。若要在运行时更改模板参数,必须在编译时直接或间接声明模板项的所有可用版本;当然,不同的方法可能适用于创建能够容纳不同类型的双链接列表。我想这取决于“声明了模板项的所有可用版本”的含义。例如,您不需要每种类型的变量(我想这就是您的意思)。
template <typename T>
void do_work() {
    le<T> list;
    // do stuff
}

int main() {
    if(use_double) {
        do_work<double>();
    }
    else if(use_int) {
        do_work<int>();
    }
}