C++ 具有可变模板参数的重载函数

C++ 具有可变模板参数的重载函数,c++,c++11,C++,C++11,我想将一些代码从使用重载函数转换为使用可变模板参数 对于不同的参数计数,现有代码具有多个模板函数: #include <iostream> #include <string> struct Boo { Boo(const std::string& name) { std::cout << "Boo constructor: " << name << std::endl; };

我想将一些代码从使用重载函数转换为使用可变模板参数

对于不同的参数计数,现有代码具有多个模板函数:

#include <iostream>
#include <string>

struct Boo
{
    Boo(const std::string& name)
    {
        std::cout << "Boo constructor: " << name << std::endl;
    };   
    static std::string CreateName(const std::string& name)
    {
        return "BooID:" + name;   
    }
};

struct Foo
{
    Foo(const std::string& name)
    {
        std::cout << "Foo constructor: " << name << std::endl;
    };
};

template <typename T>
T Construct(const std::string& name)
{
   return T(T::CreateName(name));
}

template <typename T>
T Construct(const std::string& name1, const std::string& name2)
{
   return T(T::CreateName(name1, name2));
}

// Class Foo doesn't have CreateName available
template<>
Foo Construct<Foo>(const std::string& name)
{
    return Foo{"ID:" + name};
}

int main()
{
    Construct<Boo>(std::string("123"));
    Construct<Foo>(std::string("456"));
}
如果我试图将两个模板化的
Construct()
函数替换为一个单变量模板化版本,那么我无法确定如何仅为
Foo
类指定特殊版本(在GCC 4.9.2、8.1和Visual Studio 2015上试用)

我可以通过制作一个通用模板并使用
std::enable_if_t
来限制类型,从而使其正常工作:

template <class T, typename ...Args>
T Construct(Args... args)
{
   return T(T::CreateName(args...));
}

// Class Foo needs some extra information when constructed with strings...
template<typename T, typename = std::enable_if_t<std::is_base_of<Foo, T>::value>>
T Construct(const std::string& name)
{
    return T{"ID:" + name};
}
模板
T构造(Args…Args)
{
返回T(T::CreateName(args…);
}
//类Foo在使用字符串构造时需要一些额外的信息。。。
模板
T构造(const std::string和name)
{
返回T{“ID:+name};
}

它不像原始的
模板Foo-Construct(…)
版本那么容易阅读。使用变量模板的
std::enable\u if\u t
是唯一的选项,还是有某种重载方式可以提供所需的行为?

这里的问题是专门化必须与基本模板匹配

您的基本模板将被推断为
构造
,您的专业化必须与此匹配才能被视为有效

如果您将专门化更改为

template<>
Foo Construct<Foo, std::string>(std::string name)
{
    return Foo{"ID:" + name};
}
模板
Foo构造(std::string name)
{
返回Foo{“ID:+name};
}

它可以正常工作。

这里的问题是专门化必须与基本模板匹配

您的基本模板将被推断为
构造
,您的专业化必须与此匹配才能被视为有效

如果您将专门化更改为

template<>
Foo Construct<Foo, std::string>(std::string name)
{
    return Foo{"ID:" + name};
}
模板
Foo构造(std::string name)
{
返回Foo{“ID:+name};
}

它可以正常工作。

问题在于不能部分专门化模板函数

我建议使用模板方法
func()

模板

struct Constr
 {
   template <typename ... Args>
   static T func (Args const & ... names)
    { return T(T::CreateName(names...)); }
 };

template <>
struct Constr<Foo>
 {
   static Foo func (std::string const & name)
    { return Foo{"ID:" + name}; }
 };
struct Constr
{
模板
静态T函数(参数常量和…名称)
{返回T(T::CreateName(names…);}
};
模板
结构施工
{
静态Foo func(std::string const&name)
{返回Foo{“ID:+name};}
};
电话变成了电话

Constr<Boo>::func(std::string("123"));
Constr<Foo>::func(std::string("456"));
Constr::func(std::string(“123”);
Constr::func(std::string(“456”);

问题在于不能部分专门化模板函数

我建议使用模板方法
func()

模板

struct Constr
 {
   template <typename ... Args>
   static T func (Args const & ... names)
    { return T(T::CreateName(names...)); }
 };

template <>
struct Constr<Foo>
 {
   static Foo func (std::string const & name)
    { return Foo{"ID:" + name}; }
 };
struct Constr
{
模板
静态T函数(参数常量和…名称)
{返回T(T::CreateName(names…);}
};
模板
结构施工
{
静态Foo func(std::string const&name)
{返回Foo{“ID:+name};}
};
电话变成了电话

Constr<Boo>::func(std::string("123"));
Constr<Foo>::func(std::string("456"));
Constr::func(std::string(“123”);
Constr::func(std::string(“456”);

不要专门化函数模板。最简单的方法是遵循类模板:

template <typename T, typename... Args>
T Construct(Args&&... args) {
    return ConstructorImpl<T>::apply(std::forward<Args>(args)...);
}

(虽然这不会检查它是否实际返回
t

不要专门化函数模板。最简单的方法是遵循类模板:

template <typename T, typename... Args>
T Construct(Args&&... args) {
    return ConstructorImpl<T>::apply(std::forward<Args>(args)...);
}

(尽管这不会检查它是否实际返回了
t

看起来您尝试的专门化应该是
Foo-Construct
@SamVarshavchik-我忘了提到我已经尝试过了,我会更新。谢谢。看起来你尝试的专门化应该是
Foo-Construct
@SamVarshavchik-我忘了提到我尝试过,我会更新的。谢谢。如果你不能部分专门化一个模板函数,那就完全专门化它。比我的解决方案更好。如果你不能部分专门化一个模板函数,就完全专门化它。比我的解决方案好。
template <typename T, typename... Args>
auto Construct(Args&&... args)
    -> decltype(ConstructorImpl<T>::apply(std::forward<Args>(args)...))
{
    return ConstructorImpl<T>::apply(std::forward<Args>(args)...);
}