AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77673096
Accepted
比尔盖子
比尔盖子
Asked: 2023-12-17 10:02:06 +0800 CST2023-12-17 10:02:06 +0800 CST 2023-12-17 10:02:06 +0800 CST

Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

  • 772

Preciso definir um modelo C++ que aceite várias coordenadas 3D como parâmetros. Quando todas as dimensões destas coordenadas são definidas como variáveis ​​inteiras separadas, a lista de parâmetros se tornaria excessivamente longa - 3 coordenadas precisam de 9 parâmetros, o que torna o modelo difícil de usar.

Portanto, é altamente desejável declarar os modelos de forma a usar matrizes em tempo de compilação. Seus argumentos padrão também devem ser declarados diretamente no local da declaração do modelo como valores, em vez de nomes de variáveis.

Após algumas experiências, para minha surpresa, descobri que o GCC 13 aceitará o seguinte programa C++ com std=c++20:

#include <cstdio>
#include <array>

template <
    std::array<int, 3> offset = {0, 0, 0}
>
struct Array
{
    void operator() (int i, int j, int k) 
    {
        printf("(%d, %d, %d)\n", i + offset[0], j + offset[1], k + offset[2]);
    }
};

int main(void)
{
    Array arr_default;
    arr_default(0, 0, 0);

    Array<{1, 1, 1}> arr;
    arr(0, 0, 0);

    return 0;
}

No entanto, o clang 18 rejeita a lista de inicialização com chaves como inválida:

test2.cpp:5:30: error: expected expression
    5 |         std::array<int, 3> offset = {0, 0, 0}
      |                                     ^
test2.cpp:17:8: error: no viable constructor or deduction guide for deduction of template arguments of 'Array'
   17 |         Array arr_default;
      |               ^
test2.cpp:7:8: note: candidate template ignored: couldn't infer template argument 'offset'
    7 | struct Array
      |        ^
test2.cpp:7:8: note: candidate function template not viable: requires 1 argument, but 0 were provided
    7 | struct Array
      |        ^~~~~
test2.cpp:20:8: error: expected expression
   20 |         Array<{1, 1, 1}> arr;
      |               ^
3 errors generated.

Pergunta

  1. É realmente um programa C++ legal? Se for, que sintaxe devo usar para convencer o clang a aceitá-lo? Caso contrário, devo relatar um bug do GCC por aceitá-lo inquestionavelmente?

  2. Existe uma forma alternativa e mais compatível de atingir meus objetivos? O uso std::arraynão é necessário, quaisquer outros métodos com efeito equivalente também são aceitáveis.

c++
  • 2 2 respostas
  • 338 Views

2 respostas

  • Voted
  1. Best Answer
    user12002570
    2023-12-17T11:26:38+08:002023-12-17T11:26:38+08:00

    Problema

    Este é o CWG 2450 e/ou CWG 2049 e , embora a gramática atual não permita isso, propõe-se que seja permitido/válido pelo motivo mencionado abaixo. Isso significa que o Gcc está apenas permitindo preventivamente a sintaxe . Do CWG 2450:

    Como os parâmetros de modelo sem tipo agora podem ter tipos de classe, parece fazer sentido permitir uma lista de inicialização entre chaves como argumento de modelo, mas a gramática não permite isso.

    (ênfase minha)

    Caso você esteja se perguntando como a gramática atual não permite isso, em temp.name#1 :

    template-argument:
        constant-expression
        type-id
        id-expression 
    

    E como {1, 1, 1}não é nenhuma das três construções listadas acima, não pode ser usado como argumento de modelo de acordo com as regras gramaticais atuais.


    Existe uma forma alternativa e mais compatível de atingir meus objetivos?

    Solução

    Você pode escrever explicitamente std::arrayantes da lista de inicialização entre chaves, conforme mostrado abaixo:

    #include <cstdio>
    #include <array>
    
    template <
    //------------------------------vvvvvvvvvv----------->added this
        std::array<int, 3> offset = std::array{0, 0, 0}
    >
    struct Array
    {
        void operator() (int i, int j, int k) 
        {
            printf("(%d, %d, %d)\n", i + offset[0], j + offset[1], k + offset[2]);
        }
    };
    
    int main(void)
    {
        Array arr_default;
        arr_default(0, 0, 0);
    //--------vvvvvvvvvv------------------->added this
        Array<std::array{1, 1, 1}> arr;
        arr(0, 0, 0);
    
        return 0;
    }
    

    Observação

    Observe também que o clang trunk também começa a aceitar o programa enquanto o gcc e o msvc já o aceitam em versões anteriores.

    • 11
  2. Pepijn Kramer
    2023-12-17T12:48:52+08:002023-12-17T12:48:52+08:00

    No C++ atual, eu esperaria que seu código fosse parecido com isto:

    #include <iostream>
    #include <format>
    #include <vector>
    
    // using namespace std; <== unlearn to use this (risk of nameclashes in big projects)
    
    // this is how you declare a structure/class template
    template<typename type_t> 
    struct vector_3d_t
    {
        type_t x;
        type_t y;
        type_t z;
    };
    
    // make new strong types (don't use `using` for this)
    struct position_3d_t : public vector_3d_t<int> {};
    struct velocity_3d_t : public vector_3d_t<int> {};
    
    position_3d_t update(const position_3d_t& position, const velocity_3d_t& velocity)
    {
        return position_3d_t 
        { 
            position.x + velocity.x,
            position.y + velocity.y,
            position.z + velocity.z 
        };
    }
    
    // Overload operator<< so ostreams (like std::cout) know
    // how to format one vector_3d_t
    template <typename type_t>
    std::ostream& operator<<(std::ostream& os, const vector_3d_t<type_t>& vector)
    {
        os << std::format("[{},{},{}]", vector.x, vector.y, vector.x );
        return os;
    }
    
    
    int main()
    {
        // C++'s vector which is dynamically resizable array
        // and this is how you can initialize multiple positios 
        // in a few lines of code. 
        std::vector<position_3d_t> positions
        {{
            {1,1,1}, 
            {2,2,2}, 
            {3,3,3}
        }};
    
        // learn about range base for loops 
        // and use them when you don't need indices
        for(const auto& position : positions)
        {
            std::cout << position << "\n";
        }
    }
    
    • -2

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve