我在库中有一个函数,它是一个可变参数模板,并被其他程序使用。
class A {
template<typename Ret,typename ... Args>
static Ret f(int id,Args&& ... args);
};
#include "A.tpl"
template<typename Ret,typename ... Args>
Ret A::f(int id,Args&& ... args)
{
//do somthing with args and id
Ret ret;
/// do somthing with ret
return ret;
}
我的问题是这个问题: 如果Ret无效,则代码不正确。 所以我尝试建立f:
的专业化template<typename ... Args>
void A::f<void,Args ...>(int id,Args&& ... args)
{
//do somthing with args and id
return;
}
template<typename Ret,typename ... Args>
Ret A::f(int id,Args&& ... args)
{
//do somthing with args and id
Ret ret;
/// do somthing with ret
return ret;
}
但是这段代码不正确。
所以我尝试拆分代码:
class A {
template<typename Ret,typename ... Args>
static Ret f(int id,Args&& ... args);
template<typname Ret>
static Ret f2();
}
#include "A.tpl"
template<typename Ret,typename ... Args>
Ret A::f(int id,Args&& ... args)
{
//do somthing with args and id
return f2<Ret>();
}
template<typename Ret>
Ret A::f2()
{
Ret ret;
/// do somthing with ret
return ret;
}
template<>
void A::f2<void>()
{
return;
}
现在代码没问题了,我的lib在.so / dll中编译得很好。
但是当我使用f(...)时,编译器只找到来自“A.tpl”的f2,而不是.so / dll中的f2(来自.cpp)。所以代码无效(再次),因为ret声明为void。
所以,如果有人有任何想法来解决这个问题......
修改
解决方案:
执行3解决方案,并添加A.tpl
template<>
void A::f2<void>();
答案 0 :(得分:2)
你不能局部专门化一个功能/方法......
您可以使用可以部分专用的辅助类。
template<typename Ret, typename ... Args> struct helper;
template<typename ... Args>
struct helper<void, Args...>
{
void operator() (int id, Args&& ... args) const { /* Implementation for void */ }
};
template<typename Ret, typename ... Args>
struct helper<Ret, Args...>
{
Ret operator() (int id, Args&& ... args) const { /* Implementation for non void case */ }
};
class A {
template<typename Ret,typename ... Args>
static Ret f(int id, Args&& ... args)
{
return helper<Ret, Args...>()(id, std::forward<Args>(args)...);
}
};
答案 1 :(得分:1)
帮助类的部分特化可能是最优雅的方式,你可以做Jarod42的答案。至于为什么你的解决方案不起作用。这是因为您需要在头文件中声明特化,以便编译器知道不使用通用模板进行实例化。
template <>
void A::f2<void>();
答案 2 :(得分:0)
我认为SFINAE可以解决您的问题,然后您可以在类型为空时禁用该函数,并在何时启用单独的函数。
在您的返回类型中使用std::enable_if
,如下所示:
template<typename Ret, typename ... Args>
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
f(int id,Args&& ... args);
这是难以阅读的,所以你可以减少这样的冗长:
template<bool Enable, class T = void>
using enable_if_t = typename std::enable_if<Enable, T>::type
template<typename Ret, typename ... Args>
enable_if_t<!std::is_void<Ret>::value, Ret> f(int id, Args&& ... args);
如果您正在使用C ++ 14,那么 enable_if_t
将被预定义。
您应该可以在Ret = void
:
template<tpyename Ret, typename ... Args>
enable_if_t<std::is_void<Ret>::value> f(int id, Args&& ... args);
在你的班级中定义如下:
class A{
public:
template<typename Ret, typename ... Args>
static enable_if_t<!std::is_void<Ret>::value, Ret> f(int id, Args&& ... args);
template<typename Ret, typename ... Args>
static enable_if_t<std::is_void<Ret>::value> f(int id, Args&& ... args);
};
然后使用相同的返回类型实现它们。
您可以在此处看到它:http://ideone.com/Wdmn5q
答案 3 :(得分:0)
标签调度在这里简洁明了
class A {
private:
template<typename Ret,typename ... Args>
static void f_impl(std::true_type /* Ret_is_void */, int id,Args&& ... args);
template<typename Ret,typename ... Args>
static Ret f_impl(std::false_type /* Ret_is_void */, int id,Args&& ... args);
public:
// forward to one of the two _impl versions above.
// based on if ret is void or not. While this seems to return void_expression
// such is valid in certain cases involving template code, including this one!
template<typename Ret,typename ... Args>
static Ret f(int id,Args&& ... args) {
return f_impl<Ret>( std::is_same<Ret,void>{}, id, std::forward<Args>(args)... );
}
};
template<typename Ret,typename ... Args>
Ret A::f_impl(std::false_type /* Ret_is_void */ int id,Args&& ... args)
{
static_assert( !std::is_same<Ret,void>::value, "this version is only valid with Ret as non-void");
//do somthing with args and id
Ret ret;
// do somthing with ret
return ret;
}
template<typename Ret,typename ... Args>
void A::f_impl(std::true_type /* Ret_is_void */ int id,Args&& ... args)
{
static_assert( std::is_same<Ret,void>::value, "this version is only valid with Ret as void");
// whatever you do when Ret is non-void
}