模板元编程 - 确定函数参数
Posted
技术标签:
【中文标题】模板元编程 - 确定函数参数【英文标题】:Template Meta programming - Determining function parameter 【发布时间】:2018-01-01 19:41:40 【问题描述】:template<bool, class T, class U>
struct IF_ELSE using type = T; ;
template<class T, class U>
struct IF_ELSE<false, T, Y> using type = U;
template<class T>
class Object
Object baz(IF_ELSE<boolean_condition<T>::value, foo_class, bar_class>::type param)
return Object(param);
;
您好,我正在尝试创建一个方法,该方法返回一个基于某些模板条件初始化的对象。上面的代码工作正常,但是我想使用默认构造函数(无参数)
template<class T>
class Object
Object baz(IF_ELSE<boolean_condition<T>::value, foo_class, void>::type param)
return Object(param);
;
但是不能使用 void 作为类型(尽管 void foo(void);
是一个有效的声明)
有没有办法做到这一点?
注释。我不想使用模板专业化。尽管这是针对此特定问题的解决方案,但仅在我当前的项目中使用专业化会很不方便。我个人更喜欢使用 IF_ELSE 而不是专业化,因为我发现它更易于理解。
我能想到的唯一解决方法是......
template<class T>
class Object
Object baz(IF_ELSE<boolean_condition<T>::value, foo_class, int>::type param = 0)
if (param == 0)
return Object();
else
return Object(param);
;
如果有人有更复杂的解决方案,那就太好了。非常感谢。
----------------------已编辑------------ ------------------
这个解决方法更好一些(受 Oisyn 启发),它或多或少结合了参数专业化和默认参数这两个领域的优点。可能也快一点,因为它避开了 if 语句。
template<class T>
class Object
public:
struct MAKE_ILLEGAL ;
template<class param>
Object(param p) /*do stuff */
Object() /* default */
template<bool b>
Object<T> baz(std::conditional_t<b, int, MAKE_ILLEGAL> param)
return Object<T>(param);
template<bool b>
Object<T> baz(std::conditional_t<b, MAKE_ILLEGAL, int> value = 0)
return Object<T>();
;
int main()
Object<double> obj;
obj.baz<false>();
【问题讨论】:
我认为没有比您的解决方法更好的选择(忽略专业化)。此外,您的IF_ELSE
可以替换为std::conditional
[_t
]。
您可以将Object
设为非模板化,而改为使用template <typename ...T> Object baz(T &&... params)
,但我不确定它是否适用于您的设计。
你能做到auto f = []()->void ;
,然后在模板参数中传递void
而不是decltype(someFunc())
然后你可以创建一个别名:template <bool A, typename B, typename C> using IF_ELSE = std::conditional_t<A,B,C>;
。那么你就不需要一直写::type
了。
@JosephFranciscus,conditional
这个名字已经在 C++ 模板元程序员中建立起来。使用不同的名称需要任何人阅读代码来了解这是什么,然后意识到它只是std::conditional
。
【参考方案1】:
EDIT 显然,您不允许在依赖于类型的上下文中使用解析为 void
的东西作为函数参数。我已经使用不同的解决方案相应地编辑了我的答案。原始答案可以在下面阅读。
// A helper that always yields true so we can make the condition type-dependent
// on arbitrary template parameters
template<class T>
constexpr bool true_v = true;
template<class T>
class Object
public:
template<class U = void, std::enable_if_t<Condition<T>::value && true_v<U>, int> = 0>
Object baz(foo_class param)
return Object(param);
template<class U = void, std::enable_if_t<!Condition<T>::value && true_v<U>, int> = 0>
Object baz()
return Object();
;
只要我们不处理诸如复制/移动 ctor 和复制/移动赋值运算符(可能未模板化)之类的特殊方法,我们始终可以应用常规 SFINAE 技巧。我们只需要使用默认模板参数模板化baz
,并确保用于std::enable_if
的条件类型依赖于该方法的模板参数(而不仅仅是Object<T>
中的T
)
Live version
原答案
template<class T>
class Object
private:
struct dummy ;
public:
Object baz(std::conditional_t<Conditional<T>::value, foo_class, dummy> param)
return Object(param);
Object baz(std::conditional_t<Conditional<T>::value, dummy, void>)
return Object();
;
我们的想法是创建两个重载,一个用于单个参数,一个用于无参数。通过选择性地将参数替换为不可访问的虚拟类型,您可以确保在不合适的情况下永远无法调用该重载。
【讨论】:
所以这不起作用,因为你不能使用 void 作为类型(在 c++14 和 c++17 中编译错误)invalid parameter type ‘std::conditional_t<false, Object<double>::MAKE_ILLEGAL, void> aka void
但你可以这样做....(检查编辑答案)
我会暂时给你最好的答案,因为我认为这个问题没有实际的解决方案,你给了我灵感,让我找到了一个更干净的解决方法。 (:
@JosephFranciscus 好吧,你可以,但显然不是在依赖于类型的上下文中。所以在这种情况下它确实不起作用。真可惜。但我想我知道另一个技巧,我现在正在摆弄它,我会适当地编辑我的答案。
@JosephFranciscus 是的,这有效,这次验证了;)以上是关于模板元编程 - 确定函数参数的主要内容,如果未能解决你的问题,请参考以下文章