使用C++模板魔法实现全称量词和存在量词

4
有没有一种使用C++模板魔法(可能使用SFINAE等)来实现universalexistential量化的方法?类似于这样:
template
    <
        template <typename Argument> class Predicate
    >
struct UniversalQuantification
{
    static const bool value =
        /*for any Argument Predicate<Argument>::value == true ? true : false*/;
};

template
    <
        template <typename Argument> class Predicate
    >
struct ExistentialQuantification
{
    static const bool value =
        /*for some Argument Predicate<Argument>::value == true ? true : false*/;
};

我相信这根本不可能。你到底想做什么? - iavr
1
在运行时可能,但在编译时不可能,我个人认为。 - Sebastian Hoffmann
那么问题是,如果谓词对于所有类型都为_true_? 类型的数量是无限的,并且并非所有类型在编译时都已知。所以,这是不可能的。 - nosid
2
存在量化与停机问题密切相关... - Mooing Duck
1
@Constructor 代码有点长,但是这里是:template<template<typename>class pred> struct tmp { template<typename T> using map = pred<T>; };。接着是 template<typename pred_class> struct universal { static const bool value = pred_class::template map<any_type>::value; }; 当然,这里的 any_typeuniversal 的神奇变量。最后你可以尝试一下 universal<tmp<pred> > - iavr
显示剩余16条评论
4个回答

3
如果你向模板传递一组有限的可能模板参数,那么可以在编译时计算出结果。然而,对于已使用的每个参数,由于这些类型/参数是未知的,因此无法计算出结果。
这是一个有限参数集的ExistentialQuantification类的解决方案。为了实现UniversalQuantification类的行为,只需将||更改为&&即可。
template<typename Arg>
struct Pred1;

template<>
struct Pred1<float> { static const bool value = true; };

template<>
struct Pred1<double> { static const bool value = false; };

template<>
struct Pred1<long> { static const bool value = true; };


template<template <typename Argument> class Predicate, typename... Types>
struct ExistentialQuantification;

template<template <typename Argument> class Predicate, typename Arg>
struct ExistentialQuantification<Predicate, Arg>
{
    static const bool value = Predicate<Arg>::value;
};

template<template <typename Argument> class Predicate, typename Arg, typename... Types>
struct ExistentialQuantification<Predicate, Arg, Types...>
{
    static const bool value = Predicate<Arg>::value || ExistentialQuantification<Predicate, Types...>::value;
};

int main()
{
    std::cout << ExistentialQuantification<Pred1, long, double, float>::value << std::endl;
}

在这个例子中,value将被评估为true || false || true,因此当然是真的。

谢谢。它是一个有限类型集的显而易见的解决方案。在 template<> struct Pred1<long> 特化后,您忘记了分号。 - Constructor

3
好的,如果我们只是机智地思考,并且我们被允许一些限制,以下是两个程序员的约束条件,这确实很顺利地解决了问题。
1. 如果代码需要永远为真的谓词,只使用以下内容:
template<typename> struct always : std::true_type { };

2. 如果代码需要永远为假的谓词,只使用以下内容:
template<typename> struct never : std::false_type { };

现在,解决方案很简单:
template<template<typename> class>
struct UniversalQuantification : std::false_type { };

template<>
struct UniversalQuantification<always> : std::true_type { };

template<template<typename> class>
struct ExistentialQuantification : std::true_type { };

template<>
struct ExistentialQuantification<never> : std::false_type { };

你做了我命令你做的事情,但不是我想要的。 :-) - Constructor
哦,也许这就是我写“如果我们只是聪明一点”的原因 :-) - iavr
你的回答为什么没有使用 std::true_typestd::false_type - Constructor

1

如果你可以将允许类型的范围放入类型列表中,例如在 boost::mpl::vector 中使用类库 Boost.MPL,那么你的量词就只是 std::all_ofstd::any_of 的编译时版本。你可以这样定义它们:

#include <ios>
#include <iostream>
#include <type_traits>                  // is_same, is_base_of
#include <boost/mpl/end.hpp>            // end
#include <boost/mpl/find_if.hpp>        // find_if
#include <boost/mpl/lambda.hpp>         // lambda
#include <boost/mpl/logical.hpp>        // not_
#include <boost/mpl/placeholders.hpp>   // _1
#include <boost/mpl/vector.hpp>         // vector

template<typename Sequence, typename Pred>
struct all_of
:
        std::is_same< typename
                boost::mpl::find_if<
                        Sequence,
                        boost::mpl::not_<Pred>
                >::type, typename
                boost::mpl::end<Sequence>::type
        >
{};

template<typename Sequence, typename Pred>
struct none_of
:
        all_of< Sequence, boost::mpl::not_< Pred > >
{};

template<typename Sequence, typename Pred>
struct any_of
:
        boost::mpl::not_< none_of< Sequence, Pred > >
{};

struct B {}; 
struct D : B {};
struct X {};

using Universe = boost::mpl::vector<B, D, X>;
using Predicate = boost::mpl::lambda<std::is_base_of<B, boost::mpl::_1>>;

int main()
{
    std::cout << std::boolalpha;
    std::cout << all_of<Universe, Predicate>{} << "\n";
    std::cout << any_of<Universe, Predicate>{} << "\n";
}

实例演示

正如您所看到的,由于X没有B作为基类,因此普遍量化失败,但是由于DB作为基类,因此存在量化成功。


谢谢你。我认为实现这个解决方案需要一些时间。这个解决方案是否等同于使用C++11可变参数模板(可能涉及std::tuple)的解决方案? - Constructor
@Constructor 修改了我的示例以在 Coliru 上实时运行。我不建议自己编写。Boost.MPL 是一个非常好的库,一旦你掌握了它,它甚至可以与 C++98 一起使用。 - TemplateRex
谢谢你的示例。Boost是一个非常好的库,我同意你的看法。 - Constructor

1

如果我们只是讨论 n 元(可变参数)函数和逻辑运算符“与”、“或”,就像 TemplateRex 的答案中所述,这是我不使用 Boost 的首选方法:

using _true  = std::integral_constant <bool, true>;
using _false = std::integral_constant <bool, false>;

template <bool C, typename T, typename E>
using _if = typename std::conditional <C, T, E>::type;

template <typename...> struct _and;
template <typename...> struct _or;

template <typename A, typename... B>
struct _and <A, B...> : _if <A{}, _and <B...>, _false> { };

template <typename A, typename... B>
struct _or <A, B...> : _if <A{}, _true, _or <B...> > { };

template <> struct _and <> : _true { };
template <> struct _or <> : _false { };

你为什么不使用std::conditional而使用你的_if_t类模板呢?我在你的解决方案中没有看到任何谓词模板。 :-) - Constructor
好的,看一下编辑后的代码(只是出于习惯,一切都从头开始!)你看不到谓词模板,因为它只是解决方案的一部分 :-) 没关系,我现在正在准备另一个解决方案。 - iavr
我期待着它。 - Constructor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接