C++ 模板在模板函数实例化时类型未知

标签 c++ c++11 templates c++14

class BaseClass{
    public:
    std::string name;

    BaseClass(std::string typeName) : name(typeName) {};
    std::string GetType(){ return name; }
    };

template<typename T>
class DerivedClass : public BaseClass{
    public:
    T val;
    DerivedClass(std::string typeName, T arg) : BaseClass(typeName), val(arg) {};
    };

template<typename U, typename L>
void foo1(U & arg1, L & arg2)
{
    std::cout << arg1.val + arg2.val << std::endl;
}

void foo(BaseClass *arg1, BaseClass *arg2)
{
    if(arg1->GetType() == "Int")
    {
        auto p1 = (DerivedClass<int>*)arg1;
        if(arg2->GetType() == "Int")
        {
            auto p2 = (DerivedClass<int>*)arg2;
            foo1(*p1, *p2);
        }
        else if(arg2->GetType() == "Float")
        {
            auto p2 = (DerivedClass<float>*)arg2;
            foo1(*p1, *p2);
        }
        //else if () AND SO ON ........
    }
    else if(arg1->GetType() == "Float")
    {
        auto p1 = (DerivedClass<float>*)arg1;
        if(arg2->GetType() == "Int")
        {
            auto p2 = (DerivedClass<int>*)arg2;
            foo1(*p1, *p2);
        }
        else if(arg2->GetType() == "Float")
        {
            auto p2 = (DerivedClass<float>*)arg2;
            foo1(*p1, *p2);
        }
    }
    //else if () AND SO ON .....
}

int main()
{
   BaseClass *k1 = new DerivedClass<int>("Int", 2);
   BaseClass *k2 = new DerivedClass<float>("Float", 4.32);

   foo(k1, k2);

   return 0;
}

我有一些与上面的测试用例类似的问题。 在函数 foo 中,是否有更优雅的方法将多种类型解析为 ifs 的梯子来运行模板函数? 对于 1 或 2 个参数来说,if 的阶梯并没有那么糟糕,但它会变成 (参数计数)^(类型计数);

最佳答案

您可以使用一些模板魔法来为您生成if...else链。首先,编写一个通用的编译时迭代函数:

template <typename TF, typename... Ts>
void for_each_arg(TF&& f, Ts&&... xs)
{
    return (void)(int[]){(f(std::forward<Ts>(xs)), 0)...};
}

您还需要将类型绑定(bind)到字符串的东西:

template <typename T>
struct bound_type 
{ 
    using type = T; 
    std::string _name;

    bound_type(std::string name) : _name{std::move(name)} { }
};

然后您可以使用它来检查您感兴趣的类型:

void foo(BaseClass *arg1, BaseClass *arg2)
{
    const auto for_bound_types = [](auto&& f)
    { 
        return for_each_arg(std::forward<decltype(f)>(f), 
                            bound_type<int>{"Int"},
                            bound_type<float>{"Float"},
                            bound_type<double>{"Double"});
    };

    for_bound_types([&](const auto& t1)
    {
        if(arg1->GetType() != t1._name) return;

        for_bound_types([&](const auto& t2)
        {
            if(arg2->GetType() != t2._name) return;

            using t1_type = typename std::decay_t<decltype(t1)>::type;
            using t2_type = typename std::decay_t<decltype(t2)>::type;

            auto& p1 = static_cast<DerivedClass<t1_type>&>(*arg1);
            auto& p2 = static_cast<DerivedClass<t2_type>&>(*arg2);
            foo1(p1, p2);
        }); 
    }); 
}

live wandbox example


我想避免在这里使用std::string,但是编译时字符串在C++中非常困难。类似于 typestring可以用它来代替。


在 C++17 中,由于折叠表达式for_each_arg 将是多余的。 std::apply 也可用于实现 for_bound_types

const auto for_bound_types = [](auto&& f)
{ 
    return std::apply([&](auto... xs){ (f(xs), ...); }, 
        std::make_tuple(bound_type<int>{"Int"},
                        bound_type<float>{"Float"},
                        bound_type<double>{"Double"}));
};

关于C++ 模板在模板函数实例化时类型未知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42809955/

相关文章:

c++ - 防止为非常量对象调用 const 函数

c++ - 未解析的模板参数

c++ - 显式函数模板特化选择了错误的特化

c++ - Boost::unordered_map 与初始化列表?

c++ - 如何正确清除内存?

c++ - 当 STL 容器对象的值不可复制构造时,如何将其附加/复制到另一个对象,例如标准::线程

javascript - 如何替换 Javascript 模板字符串中的变量?

c++ - 我的循环缓冲区出了什么问题

c++ - VC++ 以编程方式排除特定代码行

C++ - MATLAB : updating a Sparse Matrix blockwise