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

问题描述 投票:0回答:1
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);是有效的decleration)

反正有没有这样做?

笔记。我不想使用模板专业化。虽然这是针对这个特定问题的解决方案,但在我当前的项目中使用专业化会很不方便。我个人更喜欢使用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);

   }
};

如果有人有一个更复杂的解决方案,那将是伟大的。非常感谢。

---------------------------------- EDITED --------------- ---------------

这种解决方法更好一些(受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>();
}
c++ templates template-meta-programming
1个回答
2
投票

编辑显然,你不允许在类型相关的上下文中使用解析为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(); }
};

只要我们不处理特殊方法,如复制/移动ctors和复制/移动赋值操作符(可能没有模板化),我们总是可以应用常规的SFINAE技巧。我们只需要使用默认模板参数来模板化baz,并确保用于std::enable_if的条件依赖于该方法的模板参数(而不仅仅是T中的Object<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(); }
};

我们的想法是创建两个重载,一个用于单个参数,一个用于无。通过有选择地用不可访问的虚拟类型替换参数,您可以确保在不合适时永远无法调用该过载。


推荐问答