2017-03-12 1 views
11

Prenez le code suivant:Quelle est la bonne utilisation d'un foncteur standard constexpr?

#include <iostream> 
#include <functional> 

template <template<typename> class Op> 
auto applyOp(const uint8_t lhs, const uint8_t rhs) { 
    constexpr Op<uint8_t> op; 

    return op(lhs, rhs); 
} 

int main() { 
    std::cout << +applyOp<std::bit_and>(19, 180) << std::endl; 
} 

Lorsque vous utilisez g++, cette compile, et fonctionne très bien. Cependant clang++ donne une erreur:

test.cpp:5:27: error: default initialization of an object of const type 'const bit_and<uint8_t>' (aka 'const bit_and<unsigned char>') without a user-provided default constructor 
    constexpr Op<uint8_t> op; 
         ^
          {} 
test.cpp:11:19: note: in instantiation of function template specialization 'applyOp<std::bit_and>' requested here 
    std::cout << +applyOp<std::bit_and>(19, 180) << std::endl; 
       ^
1 error generated. 

Je pris un coup d'oeil au code source pour BIT_AND:

// Copyright (C) 2001-2016 Free Software Foundation, Inc. 
// 
// This file is part of the GNU ISO C++ Library. This library is free 
// software; you can redistribute it and/or modify it under the 
// terms of the GNU General Public License as published by the 
// Free Software Foundation; either version 3, or (at your option) 
// any later version. 

// This library is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
// GNU General Public License for more details. 

// Under Section 7 of GPL version 3, you are granted additional 
// permissions described in the GCC Runtime Library Exception, version 
// 3.1, as published by the Free Software Foundation. 

// You should have received a copy of the GNU General Public License and 
// a copy of the GCC Runtime Library Exception along with this program; 
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 
// <http://www.gnu.org/licenses/>. 

/* 
    * 
    * Copyright (c) 1994 
    * Hewlett-Packard Company 
    * 
    * Permission to use, copy, modify, distribute and sell this software 
    * and its documentation for any purpose is hereby granted without fee, 
    * provided that the above copyright notice appear in all copies and 
    * that both that copyright notice and this permission notice appear 
    * in supporting documentation. Hewlett-Packard Company makes no 
    * representations about the suitability of this software for any 
    * purpose. It is provided "as is" without express or implied warranty. 
    * 
    * 
    * Copyright (c) 1996-1998 
    * Silicon Graphics Computer Systems, Inc. 
    * 
    * Permission to use, copy, modify, distribute and sell this software 
    * and its documentation for any purpose is hereby granted without fee, 
    * provided that the above copyright notice appear in all copies and 
    * that both that copyright notice and this permission notice appear 
    * in supporting documentation. Silicon Graphics makes no 
    * representations about the suitability of this software for any 
    * purpose. It is provided "as is" without express or implied warranty. 
    */ 

[ ... content omitted ... ] 

template<typename _Arg1, typename _Arg2, typename _Result> 
    struct binary_function 
    { 
     /// @c first_argument_type is the type of the first argument 
     typedef _Arg1  first_argument_type; 

     /// @c second_argument_type is the type of the second argument 
     typedef _Arg2  second_argument_type; 

     /// @c result_type is the return type 
     typedef _Result result_type; 
    }; 

[ ... content omitted ... ] 

#if __cplusplus > 201103L 
    template<typename _Tp = void> 
    struct bit_and; 

    [ ... content omitted ... ] 

#endif 

    [ ... content omitted ... ] 

    // _GLIBCXX_RESOLVE_LIB_DEFECTS 
    // DR 660. Missing Bitwise Operations. 
    template<typename _Tp> 
    struct bit_and : public binary_function<_Tp, _Tp, _Tp> 
    { 
     _GLIBCXX14_CONSTEXPR 
     _Tp 
     operator()(const _Tp& __x, const _Tp& __y) const 
     { return __x & __y; } 
    }; 

    [ ... content omitted ... ] 

Pour ce que je peux dire, un constructeur par défaut doit être généré ici. Il est intéressant de noter que le message d'erreur demande spécifiquement un "constructeur par défaut fourni par l'utilisateur" plutôt qu'un simple "constructeur par défaut".

Modification de la ligne incriminée à utiliser l'initialisation uniforme conduit le code à travailler avec les deux compilateurs:

- constexpr Op<uint8_t> op; 
+ constexpr Op<uint8_t> op { }; 

Ma question est, est clang++ correcte pour exiger ces accolades supplémentaires, ou est-g++ raison de ne pas?

Extra info

avec commande g++ Compiler:

g++ test.cpp -Werror -Wall -pedantic -std=c++14 

avec commande clang++ Compiler:

clang++ test.cpp -Werror -Wall -pedantic -std=c++14 

exécution de la commande d'application:

./a.out 

Lieu de bit_and Définition:

/usr/include/c++/6.2.0/bits/stl_function.h 

En ce qui concerne le drapeau possible duplicate, je ne crois pas que ce soit un doublon car cette question demande pourquoi cette règle existe, alors que ma question était plus découvrir certaines la règle en premier lieu et quel compilateur est correct dans son application. De plus, les réponses au duplicata allégué ne répondent pas à ma question.

+1

Fonctionne-t-il avec 'constexpr Op op {};'? –

+0

@DanielJour oui, merci! Question mise à jour – OMGtechy

+0

Copie possible de [Pourquoi C++ nécessite un constructeur par défaut fourni par l'utilisateur pour construire par défaut un objet const?] (Http://stackoverflow.com/questions/7411515/why-does-c-require-a-user-provided -default-constructor-to-default-construct-a) – Oktalist

Répondre

9

L'original C++ 14 libellé [dcl.init] exigeait que:

If a program calls for the default-initialization of an object of a const -qualified type T , T shall be a class type with a user-provided default constructor.

Par conséquent, avoir simplement un constructeur par défaut est insuffisant. Il devait également avoir été fourni par l'utilisateur. Clang a implémenté cette règle, qui nécessitait constexpr Op<uint8_t> op{};, mais pas gcc - permettant l'initialisation par défaut dans ce cas.

Cependant, cette formulation a été révisée récemment dans p0490. Le nouveau libellé, appliqué rétroactivement à C++ 14, se lit comme suit:

A class type T is const-default-constructible if default-initialization of T would invoke a user-provided constructor of T (not inherited from a base class) or if
— each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X is const-default-constructible,
— if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
— if T is a not a union, for each anonymous union member with at least one non-static data member (if any), exactly one non-static data member has a default member initializer, and each potentially constructed base class of T is const-default-constructible.

If a program calls for the default-initialization of an object of a const-qualified type T, T shall be a const-default-constructible class type or array thereof.

Op<uint8_t> est const-default-constructible (pour la raison triviale qu'il n'a pas de membres de données non statiques), de sorte que vous pouvez choisir par défaut -initialiser.Maintenant, C++ 14 permettra:

constexpr Op<uint8_t> op; 

En effet, nous sommes passés d'un bug gcc (permettant l'initialisation-par défaut) à un bug clang (la rejetant).

+0

Donc, d'après ce que je comprends, la norme C++ 14 sera modifiée pour refléter cette nouvelle formulation, ou sera-t-elle ciblée sur une future version (comme C++ 1z)? (Je ne suis pas familier avec le processus de défaut) – OMGtechy

+1

@OMGtechy C++ 14 ne sera pas changé en tant que tel, mais comme le comité l'a décrit comme un défaut de C++ 14, les implémentations peuvent appliquer la nouvelle règle lors de la compilation dans Mode C++ 14. – Oktalist