неинтегральные константы

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

static const std::string Ten = "10";

Это компилирует, но является нежелательным, поскольку каждая единица компиляции теперь имеет свою собственную копию Десять.

const std::string Ten = "10";

Это скомпилирует, но перестанет работать с ошибкой компоновщика для, умножаются определенный Десять.

constexpr std::string Ten = "10"s;

Это работало бы, но только если строковый конструктор был constexpr также. Это будет всего лишь, я не могу рассчитывать на каждую неинтегральную константу, чтобы иметь constexpr конструктора..., или могу я?

extern const std::string Ten = "10";

Это, кажется, работает, но я боюсь, что получу ошибку компоновщика, если я буду дышать на ней неправильно.

inline const std::string Ten( ) { return "10"; }

Это имеет все, что я хочу кроме чистого синтаксиса. Плюс теперь я должен отослать константу как вызов функции, Ten().

inline const std::string = "10";

Это, кажется, идеальное решение. Конечно, inline переменные не позволяются стандартом.

  • Есть ли что-то в стандарте C++, в котором говорится, что версия экстерна должна работать, или я просто удачлив, что это работает с GCC?
  • Существует ли неопровержимый довод для не разрешения встроенных переменных?
  • Существует ли лучший путь с C++ 03 или будет лучший путь в C++ 0x?
16
задан deft_code 24 April 2013 в 17:26
поделиться

5 ответов

Вы, кажется, их перепутаны.

Вы правы в

static const std::string Ten = "10"; 

версии. Он будет «работать», но он создаст отдельный объект в каждом блоке перевода.

Версия без Static будет иметь тот же эффект. Это не будет производить ошибки линкера, но определит отдельный объект в каждом блоке перевода. На языке C ++ Const объекты имеют внутреннюю связь по умолчанию, что означает, что

const std::string Ten = "10"; // `static` is optional

точно эквивалентно предыдущей версии с Static .

Версия с External и инициализатор

extern const std::string Ten = "10"; // it's a definition!

будет создавать определение объекта с внешним связью (это определение из-за наличия инициализатора). Эта версия приведет к ошибкам линкера, поскольку вы получите несколько определений объекта с внешним соединением - нарушением ODR.

Вот как вы можете сделать это:

Для достижения того, что вы пытаетесь достичь, вам необходимо , вы должны объявить вашу константу в файле заголовка

extern const std::string Ten; // non-defining declaration

, а затем определить его (с помощью инициализатора ) в одном и только один из файлов реализации

extern const std::string Ten = "10"; // definition, `extern` optional

(если константа предварительно объявлена ​​как Extern , то Внешнее в определении необязательно. Даже без явного extern Определите объект Const с внешним связью.)

27
ответ дан 30 November 2019 в 15:56
поделиться

Я не знаю, есть ли лучший путь в C ++, но лучший путь в C (который также будет работать в C ++), является одним из тех, которые вы перечислены.

имеют отдельный блок компиляции (например, TEN.CPP ), удерживая только данные:

const std::string Ten = "10";

и файл заголовка (например, Ten.h ), объявляющий его Может использоваться в другом месте:

extern const std::string Ten;

Тогда вам просто нужно обеспечить любую единицу компиляции, который хочет использовать его, включают в себя файл заголовка (например, Ten.h ), и любой исполняемый файл, который хочет использовать его ссылку с Отдельный блок компиляции (например, Ten.o ).

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

Я не знаю Почему Вы утверждаете:

, но я боюсь, я получу ошибку линкера, если я дышу на нем неправильно

Это принято практика из . Длинно назад, и вы должны знать, как все эти вещи вписываются вместе, если вы хотите позвонить себе программистом C ++ (без оскорбления).

10
ответ дан 30 November 2019 в 15:56
поделиться

Я думаю, что другие ответы здесь лучше, но если вы мертвы на это все с заголовками, вы можете эффективно встроенный объект (как вы конкретно спрашиваете) с простой функцией обертки.

inline const std::string &get_ten() {
    static const std::string ten = "10";
    return ten;
}

Там будет только одна строка , инициализирована один раз, и вам не нужно ничего за пределами файла заголовка.

1
ответ дан 30 November 2019 в 15:56
поделиться

(c + +/cli - это новое имя) Для безупречной работы можно использовать собственный код, управляемый мусором, c # и даже выполнять обратные вызовы. Обратно можно создавать управляемые типы и взаимодействовать с ними из c++.

Позволяет разработчикам легко переходить на c #, чтобы контролировать время быстрой сборки и т. д., например, xna, связываясь с собственными библиотеками, как упомянуто!

-121--4321119-

Наборы переменной среды MAKEFLAGS на -j 8 . Если вы используете csh или tcsh, вы можете сделать это с помощью setenv MAKEFLAGS '-j 8' . Если используется bash, это можно сделать с помощью export MAKEFLAGS = '-j 8' . Эту команду можно поместить в файл запуска оболочки, например, в файл .cshrc или .bashrc (в домашнем каталоге).

Внимание! Установка такого значения по умолчанию будет применяться ко всем вызовам make, в том числе при «создании» проекта, отличного от вашего собственного, или при выполнении сценария, который вызывает make. Если проект не был спроектирован должным образом, могут возникнуть проблемы при его построении с параллельным выполнением нескольких заданий.

-121--2620732-

Версия extern близка к нужной. Здесь:

// in the file tenconstant.cpp
const std::string Ten = "10";

// in the file tenconstant.h
extern const std::string Ten;

// in your file
#include "tenconstant.h"

// do stuff with Ten

Вы должны быть определены один раз для линкера, что является целью myconstants.cpp , но объявлено везде, где вы используете его, что является целью myconstants.h . Это может показаться немного громоздким для одной переменной, но для более крупного проекта, вы, вероятно, будет хороший заголовок, который используется много, что вы можете воткнуть это.

6
ответ дан 30 November 2019 в 15:56
поделиться

Это фундаментальная концепция объектно-ориентированного программирования -- полиморфизм. ( википедия )

Короткий ответ заключается в том, что с помощью интерфейса класса A можно дать классу A любую реализацию IMyInterface .

Это также форма свободной связи ( wikipedia ) - где у вас много классов, но они явно не полагаются друг на друга - только абстрактное понятие набора свойств и методов, которые они предоставляют (интерфейс).

Параметры настройки привязки -121--1244324-

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

<TextBlock Text="Assign To: "/>
<TextBlock Text="{Binding Name}"/>

pls, проверьте, будет ли пример ниже работать для вас; Также эта ссылка WPF Toolkit DataGrid Part IV: TemplateColumns и Row Grouping может быть полезна для вас

code:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var dataProvider = (CollectionViewSource)FindResource("CVS");
        dataProvider.Source = Test.GetTests();
    }
}

public class Test
{
    public string   Assign_To { get; set; }
    public string   Test0 { get; set; }
    public int      Test1 { get; set; }

    public static List<Test> GetTests()
    {
        List<Test> tests = new List<Test>();

        tests.Add(new Test { Assign_To = "a", Test0 = "aaaa", Test1 = 1 });
        tests.Add(new Test { Assign_To = "a", Test0 = "bbbb", Test1 = 1 });
        tests.Add(new Test { Assign_To = "b", Test0 = "cccc", Test1 = 2 });

        return tests;
    }
}

xaml:

<Window.Resources>    
    <CollectionViewSource x:Key="CVS" >
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Assign_To"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>

    <Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type GroupItem}">
                    <Expander IsExpanded="True">
                        <Expander.Header>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="Assign To: "/>
                                <TextBlock Text="{Binding Name}"/>
                            </StackPanel>
                        </Expander.Header>
                        <ItemsPresenter />
                    </Expander>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>    
</Window.Resources>

<Grid>        
    <DataGrid 
        ItemsSource="{Binding Source={StaticResource CVS}}"            
        HorizontalScrollBarVisibility="Hidden" SelectionMode="Extended"
        AutoGenerateColumns="False"  
        Name="dataGrid1">    
        <DataGrid.GroupStyle>
            <GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
                <GroupStyle.Panel>
                    <ItemsPanelTemplate>
                        <DataGridRowsPresenter/>
                    </ItemsPanelTemplate>
                </GroupStyle.Panel>
            </GroupStyle>
        </DataGrid.GroupStyle>    
        <DataGrid.Columns>
            <DataGridTextColumn Header="Test0" Binding="{Binding Path=Test0}" />
            <DataGridTextColumn Header="Test1" Binding="{Binding Path=Test1}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>
-121--3250476-

Создание статического определяемого пользователем типа в этом пути является плохой идеей. Невозможно управлять порядком создания экземпляров при наличии нескольких таких определяемых пользователем типов. Это не проблема в небольшом проекте, но не все проекты малы. Лучше сделать статику всех простых старых типов данных - необработанных указателей - и инициализировать их каким-то подходящим способом, чтобы указать на нужные экземпляры при запуске программы или когда они нужны. Это дает вам контроль.

Ваш вопрос гласит, что эти типы не обязательно должны быть константами времени компиляции. Если это так, и у вас есть многопоточная программа, ваши объекты должны быть защищены от одновременного доступа из нескольких потоков. Если некоторые объекты не являются защищенными от потоков, то в дополнение к самому объекту для защиты его состояния необходим объект-мьютекс, который должен иметь ту же связь и нуждается в инициализации. Все это усложняет глобальное состояние вашей программы в том, что может быть недопустимым путем.

2
ответ дан 30 November 2019 в 15:56
поделиться
Другие вопросы по тегам:

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