模板元编程 - 确定函数参数

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 &lt;typename ...T&gt; Object baz(T &amp;&amp;... params),但我不确定它是否适用于您的设计。 你能做到auto f = []()-&gt;void ;,然后在模板参数中传递void而不是decltype(someFunc()) 然后你可以创建一个别名:template &lt;bool A, typename B, typename C&gt; using IF_ELSE = std::conditional_t&lt;A,B,C&gt;;。那么你就不需要一直写::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&lt;T&gt; 中的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&lt;false, Object&lt;double&gt;::MAKE_ILLEGAL, void&gt; aka void 但你可以这样做....(检查编辑答案) 我会暂时给你最好的答案,因为我认为这个问题没有实际的解决方案,你给了我灵感,让我找到了一个更干净的解决方法。 (: @JosephFranciscus 好吧,你可以,但显然不是在依赖于类型的上下文中。所以在这种情况下它确实不起作用。真可惜。但我想我知道另一个技巧,我现在正在摆弄它,我会适当地编辑我的答案。 @JosephFranciscus 是的,这有效,这次验证了;)

以上是关于模板元编程 - 确定函数参数的主要内容,如果未能解决你的问题,请参考以下文章

基于C++11模板元编程实现Scheme中的list及相关函数式编程接口

提高性能及操作硬件的能力

使用模板元编程检测函数可以采用的最大参数数

Item 48:了解模板元编程

C++模板元编程深度解析:探索编译时计算的神奇之旅

什么样的C++模板编程可以称为“元编程”? [关闭]