2012-07-27 3 views
7

У меня есть класс под названием AppSettings, где у меня есть массив с диапазоном частот заметок. Я получаю несколько ошибок с приведенным ниже кодом, и я не уверен, в чем проблема.объявление const массива в файле заголовка C++

Сообщения об ошибках:

  • static data member of type 'const float [36] must be initialized out of line
  • A brace enclosed initializer is not allowed here before '{' token
  • Invalid in-class initialization of static data member of non-integral type

И код:

class AppSettings{ 

public: 
    static const float noteFrequency[36] = { 
    // C  C#  D  D#  E  F  F#  G  G#  A  A#  B 
     130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 223.08, 246.94, 
     261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88, 
     523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77 
    }; 

}; 

Как й e name указывает, что это всего лишь заголовочный файл с некоторыми настройками и значениями, которые мне нужны во всем приложении.

+2

Примечание частоты C++ просто рассчитывается по математической формуле. Сделайте это динамически при запуске. –

+0

Это хорошая идея, я посмотрю – networkprofile

+0

@Rok Kralj, зачем тратить время на вычисление статических данных, которые никогда не изменятся. – bazz

ответ

16

Вы не можете определить значение класса static класса. Вы должны иметь такую ​​строку в классе:

class AppSettings 
{ 
public: 
    static const float noteFrequency[]; 

, а затем в файле реализации для класса (AppSettings.cpp возможно):

const float AppSettings::noteFrequency[] = { /* ... */ }; 

Кроме того, вам не нужно указать номер в пределах [] здесь, потому что C++ достаточно умен, чтобы подсчитать количество элементов в вашем значении инициализации.

+0

-1 Как я пишу это, совет - просто разместить инициализатор после класса. С этим можно было бы вообще нарушить одно правило определения. То есть для общего случая линкер будет протестовать решительно. –

+2

@ Cheersandhth.-Alf Это не имеет никакого отношения к вопросу. Этот ответ хорошо написан и краток. Не помещать реализацию в файлы заголовков - это просто здравый смысл для языка. Я мог бы отметить половину решений на SO, потому что люди оставляют вещи краткими, это не делает это неправильно. Хотя это может сделать ваш ответ лучше, чем этот, если вы предоставили ** дополнительный ** контент. –

+0

@woote: Конечно, правильность ответа имеет значение. с другой стороны, ваша точка зрения о том, насколько хорошо написана, на мой взгляд не имеет значения. –

8

C++ 03 не поддерживает определения в классе сложных данных, таких как массивы констант.

Чтобы поместить такое определение в области видимости пространства имен в файле заголовка, и избежать нарушения One Definition Rule, вы можете использовать специальное исключение для шаблонных классов, следующим образом:

#include <iostream> 
using namespace std; 

//----------------------------------------- BEGIN header file region 
template< class Dummy > 
struct Frequencies_ 
{ 
    static const double noteFrequency[36]; 
}; 

template< class Dummy > 
double const Frequencies_<Dummy>::noteFrequency[36] = 
{ 
    // C  C#  D  D#  E  F  F#  G  G#  A  A#  B 
    130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 223.08, 246.94, 
    261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88, 
    523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77 
}; 

class AppSettings 
    : public Frequencies_<void> 
{ 
public: 
}; 
//----------------------------------------- END header file region 

int main() 
{ 
    double const a = AppSettings::noteFrequency[21]; 

    wcout << a << endl; 
} 

Есть также некоторые другие методы, которые могут быть использованы:

  • Встроенная функция, создающая ссылку на массив (или используемый в качестве индексатора).

  • Размещение определения в отдельно скомпилированном файле.

  • Просто вычислить числа при необходимости.

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

+0

@MooingDuck: хорошая идея, но это дает мне несколько ошибок связывания определения? после полной специализации класс является вещественным классом. и я думаю, никаких специальных освобождений ODR для него тогда. –

+0

@MooingDuck: он должен компилироваться, но он дублирует данные: один раз для экземпляра 'false' и один раз для экземпляра' true'. возможно, компилятор достаточно умный, чтобы оптимизировать это. но если кто-то хочет избавиться от возможного непреднамеренного дублирования данных, тогда я думаю, что обычным «перечислением» без определенных элементов будет путь. –

+0

@MooingDuck: оба визуальных C++ и g ++ оптимизируют это. но каждый экземпляр шаблона является его собственным классом. Я думаю, что в той мере, в которой данные не дублируются здесь, это тоже не дублируется шаблоном в моем ответе? –

10

Это прекрасно работает в 11

class AppSettings{ 

public: 
    static constexpr float noteFrequency[36] = { 
// C  C#  D  D#  E  F  F#  G  G#  A  A#  B 
    130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 223.08, 246.94, 
    261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88, 
    523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77 
    }; 

}; 
Смежные вопросы