Можно ли проверить, что-то является constexpr? [Дубликат]

Вы должны создать класс, который наследует от QSortFilterProxyModel, и перезаписать метод filterAcceptsRow, где возвращается False, если хотя бы один элемент не выполняется, и True, если все выполнено.

class SortFilterProxyModel(QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        QSortFilterProxyModel.__init__(self, *args, **kwargs)
        self.filters = {}

    def setFilterByColumn(self, regex, column):
        self.filters[column] = regex
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        for key, regex in self.filters.items():
            ix = self.sourceModel().index(source_row, key, source_parent)
            if ix.isValid():
                text = self.sourceModel().data(ix).toString()
                if not text.contains(regex):
                    return False
        return True

Пример:

def random_word():
    letters = "abcdedfg"
    word = "".join([choice(letters) for _ in range(randint(4, 7))])
    return word


class Widget(QWidget):
    def __init__(self, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        self.setLayout(QVBoxLayout())

        tv1 = QTableView(self)
        tv2 = QTableView(self)
        model = QStandardItemModel(8, 4, self)
        proxy = SortFilterProxyModel(self)
        proxy.setSourceModel(model)
        tv1.setModel(model)
        tv2.setModel(proxy)
        self.layout().addWidget(tv1)
        self.layout().addWidget(tv2)

        for i in range(model.rowCount()):
            for j in range(model.columnCount()):
                item = QStandardItem()
                item.setData(random_word(), Qt.DisplayRole)
                model.setItem(i, j, item)

        flayout = QFormLayout()
        self.layout().addLayout(flayout)
        for i in range(model.columnCount()):
            le = QLineEdit(self)
            flayout.addRow("column: {}".format(i), le)
            le.textChanged.connect(lambda text, col=i:
                                   proxy.setFilterByColumn(QRegExp(text, Qt.CaseSensitive, QRegExp.FixedString),
                                                           col))


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())
28
задан user2023370 9 November 2012 в 01:11
поделиться

5 ответов

Начиная с 2017 года, is_constexpr невозможно в C ++ 11. Это звучит странно, поэтому позвольте мне объяснить немного истории.

Сначала мы добавили эту функцию для устранения дефекта: http: //www.open-std. org / jtc1 / sc22 / wg21 / docs / cwg_defects.html # 1129

Johannes Schaub-litb разместил макрос обнаружения constexpr, который основывался на условии, что константные выражения неявно не являются исключением. Это работало на C ++ 11, но никогда не было реализовано по крайней мере некоторыми компиляторами (например, clang). Затем, как часть C ++ 17, мы оценили Удаление устаревших спецификаций исключения из C ++ 17 . В качестве побочного эффекта этой формулировки мы случайно удалили это положение. Когда основная рабочая группа обсудила вопрос о добавлении резерва, они поняли, что с этим возникли серьезные проблемы. Подробные сведения вы можете увидеть в отчете об ошибке LLVM . Поэтому вместо того, чтобы добавлять его обратно в , мы решили считать это дефектом для всех версий стандарта и ретроактивно удалить его .

Эффект от этого заключается в том, что для моего не может обнаружить, может ли выражение использоваться в качестве постоянного выражения.

11
ответ дан David Stone 23 August 2018 в 16:34
поделиться

Я однажды написал (EDIT: см. ниже ограничения и объяснения). Из https://stackoverflow.com/a/10287598/34509 :

template<typename T> 
constexpr typename remove_reference<T>::type makeprval(T && t) {
  return t;
}

#define isprvalconstexpr(e) noexcept(makeprval(e))

Однако существует много видов постоянных выражений. Вышеуказанный ответ обнаруживает постоянные выражения prvalue.


Объяснение

Выражение noexcept(e) дает false, если f e содержит

  • потенциально оцениваемый вызов функции, которая не имеет спецификацию исключения без метаданных, если вызов не является постоянным выражением,
  • потенциально оцененное выражение throw,
  • потенциально (f7) или typeid.

Обратите внимание, что шаблон функции makeprval не объявлен noexcept, поэтому вызов должен быть постоянным выражением для первого пулю не применять, и это то, что мы злоупотребляем. Нам также нужны другие патроны, но, к счастью, и throw, и метаданные dynamic_cast или typeid также не допускаются в постоянных выражениях, так что это нормально.

Ограничения

К сожалению, существует ограничение на подслою, которое может или не имеет значения для вас. Понятие «потенциально оцененное» гораздо более консервативно, чем ограничения того, что применяются постоянные выражения. Таким образом, выше noexcept может давать ложные отрицания. Он сообщит, что некоторые выражения не являются константными выражениями prvalue, хотя они и есть. Пример:

constexpr int a = (0 ? throw "fooled!" : 42);
constexpr bool atest = isprvalconstexpr((0 ? throw "fooled!" : 42));

В приведенном выше atest неверно, хотя инициализация a преуспела. Это потому, что для того, чтобы быть постоянным выражением, достаточно, чтобы «злые» непостоянные подвыражения «никогда не оценивались», хотя эти злые подвыражения являются потенциально оцененными формально.

27
ответ дан Community 23 August 2018 в 16:34
поделиться

Да, это возможно. Один из способов сделать это (что справедливо даже при недавних изменениях noexcept) - использовать правила сужения конверсии C ++ 11:

A сужение преобразования представляет собой неявное преобразование [...] из целочисленного типа или неперечисленного типа перечисления в целочисленный тип, который не может представлять все значения исходного типа, за исключением случаев, когда источником является постоянное выражение, значение которого после того, как целые акции будут вписываться в тип цели.

(акцент мой). Инициализация списка обычно запрещает сужение конверсий, и в сочетании с SFINAE мы можем создавать гаджеты для определения того, является ли произвольное выражение постоянным выражением:

// p() here could be anything
template<int (*p)()> std::true_type is_constexpr_impl(decltype(int{(p(), 0U)}));
template<int (*p)()> std::false_type is_constexpr_impl(...);
template<int (*p)()> using is_constexpr = decltype(is_constexpr_impl<p>(0));

constexpr int f() { return 0; }
int g() { return 0; }
static_assert(is_constexpr<f>());
static_assert(!is_constexpr<g>());

Живая демонстрация .

Ключ здесь состоит в том, что int{(expr, 0U)} содержит сужение преобразования от unsigned int до int (и, следовательно, плохо сформировано), , если expr не является постоянным выражением, в в этом случае все выражение (expr, 0U) является константным выражением, оцениваемое значение которого соответствует типу int.

3
ответ дан Richard Smith 23 August 2018 в 16:34
поделиться

Давайте сыграем наивную игру с идиомой SFINAE :

template <typename C> struct IsConstExpr
{
    typedef char yes;
    typedef char no[2];

    template <typename T> static constexpr yes& swallow(T) { int x[T()]; return 0; };
    template <typename T> static no& swallow(...);

    static const int value = sizeof(swallow<C>(0)) == sizeof(yes);
};

. Вышеприведенный код синтаксически неверен, но это даст нам некоторое представление. Попробуем использовать его:

constexpr int f() { return 32167; }

int g() { return 32167; }

int main()
{
   std::cout << IsConstExpr<decltype(&f)>::value << std::endl;
}

Компилятор говорит:

In instantiation of 'static constexpr IsConstExpr<C>::yes& IsConstExpr<C>::swallow(T) [with T = int (*)(); C = int (*)(); IsConstExpr<C>:
:yes = char]':

Теперь проблема очевидна: параметром шаблона является T = int (*)();

Это означает, что constexpr не является частью типа, и мы не можем его обнаружить.

-3
ответ дан Sergey K. 23 August 2018 в 16:34
поделиться

Ниже приведена реализация is_constexpr для функций , а не для произвольных выражений, для C ++ 11 и C ++ 17. Это требует, чтобы аргументы функции, которую вы хотите проверить, были конструктивными по умолчанию.

#include <type_traits>

struct A {};  // don't make it too easy, use a UDT

          A f1(A a) { return a; }  // is_constexpr -> false
constexpr A f2(A a) { return a; }  // is_constexpr -> true

// The following turns anything (in our case a value of A) into an int.
// This is necessary because non-type template arguments must be integral 
// (likely to change with C++20).
template <class T> constexpr int make_int(T &&) { return 0; }

// Helper to turn some function type (e.g. int(float)) into a function
// pointer type (e.g. int (*)(float)).
template <class T> struct signature_from;
template <class R, class... Args> struct signature_from<R(Args...)> {
    using type = R(*)(Args...);
};

// See std::void_t for the idea. This does it for ints instead of types.
template <int...> using void_from_int = void;

// The fallback case: F is not a function pointer to a constexpr function
template <class T, typename signature_from<T>::type F, class = void_from_int<>>
struct is_constexpr {
    static constexpr bool value = false;
};
// If void_from_int<make_int(F(Args()...))> doesn't lead to a substitution
// failure, then this is the preferred specialization. In that case F must
// be a function pointer to a constexpr function. If it is not, it could
// not be used in a template argument.
template <class R, class... Args, typename signature_from<R(Args...)>::type F>
struct is_constexpr<R(Args...), F, void_from_int<make_int(F(Args()...))>>
{
    static constexpr bool value = true;
};

// proof that it works:
static_assert(!is_constexpr<A(A), f1>::value, "");
static_assert( is_constexpr<A(A), f2>::value, "");

#if __cplusplus >= 201703
// with C++17 the type of the function can be deduced:
template<auto F> struct is_constexpr2 : is_constexpr<std::remove_pointer_t<decltype(F)>, F> {};

static_assert(!is_constexpr2<f1>::value, "");
static_assert( is_constexpr2<f2>::value, "");
#endif

См. Это в действии в https://godbolt.org/g/rdeQme .

1
ответ дан Vir 23 August 2018 в 16:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: