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

时间:2018-01-01 19:41:40

标签: c++ templates template-meta-programming

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>();
}

1 个答案:

答案 0 :(得分: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 { {1}})

Live version

原始回答

Object<T>

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