Причина foldl'
предпочтена foldl
для 99% всего использования, то, что это может работать в постоянном пространстве за большей частью использования.
Берут функцию sum = foldl['] (+) 0
. Когда foldl'
используется, сумма сразу вычисляется, таким образом применение sum
к бесконечному списку будет просто работать навсегда, и скорее всего в постоянном пространстве (если you’re с помощью вещей как Int
с, Double
с, Float
с. Integer
с будет использовать больше, чем постоянное пространство, если число станет больше, чем maxBound :: Int
).
С [1 110], преобразователь создается (как рецепт того, как получить ответ, который может быть оценен позже, вместо того, чтобы хранить ответ). Эти преобразователи могут поднять много пространства, и в этом случае, it’s намного лучше для оценки выражения, чем сохранить преобразователя (ведущий к стеку overflow… и продвижение Вас to… о, не берите в голову)
Hope, которая помогает.
Чтобы получить эквивалент статического конструктора, вам нужно написать отдельный обычный класс для хранения статических данных, а затем создать статический экземпляр этого обычного класса.
class StaticStuff
{
std::vector<char> letters_;
public:
StaticStuff()
{
for (char c = 'a'; c <= 'z'; c++)
letters_.push_back(c);
}
// provide some way to get at letters_
};
class Elsewhere
{
static StaticStuff staticStuff; // constructor runs once, single instance
};
Что ж, у вас может быть
class MyClass
{
public:
static vector<char> a;
static class _init
{
public:
_init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
} _initializer;
};
Не забудьте (в .cpp) следующее:
vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;
Программа по-прежнему будет связываться без второй строки, но инициализатор не будет запущен.
Как насчет создания шаблона, имитирующего поведение C #.
template<class T> class StaticConstructor
{
bool m_StaticsInitialised = false;
public:
typedef void (*StaticCallback)(void);
StaticConstructor(StaticCallback callback)
{
if (m_StaticsInitialised)
return;
callback();
m_StaticsInitialised = true;
}
}
template<class T> bool StaticConstructor<T>::m_StaticsInitialised;
class Test : public StaticConstructor<Test>
{
static std::vector<char> letters_;
static void _Test()
{
for (char c = 'a'; c <= 'z'; c++)
letters_.push_back(c);
}
public:
Test() : StaticConstructor<Test>(&_Test)
{
// non static stuff
};
};
Чтобы инициализировать статическую переменную, вы просто делаете это внутри исходного файла. Например:
//Foo.h
class Foo
{
private:
static int hello;
};
//Foo.cpp
int Foo::hello = 1;
Вы определяете статические переменные-члены аналогично тому, как вы определяете член методы.
foo.h
class Foo
{
public:
void bar();
private:
static int count;
};
foo.cpp
#include "foo.h"
void Foo::bar()
{
// method definition
}
int Foo::count = 0;
Концепция статических конструкторов была введена в Java после того, как они узнали о проблемах в C ++. Таким образом, у нас нет прямого эквивалента.
Лучшее решение - использовать типы POD, которые можно инициализировать явно.
Или сделайте ваши статические члены определенного типа, у которого есть собственный конструктор, который будет правильно его инициализировать.
//header
class A
{
// Make sure this is private so that nobody can missues the fact that
// you are overriding std::vector. Just doing it here as a quicky example
// don't take it as a recomendation for deriving from vector.
class MyInitedVar: public std::vector<char>
{
public:
MyInitedVar()
{
// Pre-Initialize the vector.
for(char c = 'a';c <= 'z';++c)
{
push_back(c);
}
}
};
static int count;
static MyInitedVar var1;
};
//source
int A::count = 0;
A::MyInitedVar A::var1;
Нет необходимости в init ()
функция std :: vector
может быть создана из диапазона:
// h file:
class MyClass {
static std::vector<char> alphabet;
// ...
};
// cpp file:
#include <boost/range.hpp>
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
std::vector<char> MyClass::alphabet( boost::begin( ::alphabet ), boost::end( ::alphabet ) );
Обратите внимание, однако, что статика типа класса вызывает проблемы в библиотеках, поэтому там их следует избегать.
C ++ 11 Обновление
Начиная с C ++ 11, вы можете сделать это вместо этого:
// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };
Это семантически эквивалентно решению C ++ 98 в исходном ответе, но вы не можете использовать строковый литерал справа -сайд, так что не совсем лучше. Однако если у вас есть вектор любого другого типа, кроме char
, wchar_t
,
В файле .h:
class MyClass {
private:
static int myValue;
};
В файле .cpp:
#include "myclass.h"
int MyClass::myValue = 0;
При попытке скомпилировать и использовать класс Elsewhere
(из Earwicker's answer) я получаю:
error LNK2001: unresolved external symbol "private: static class StaticStuff Elsewhere::staticStuff" (?staticStuff@Elsewhere@@0VStaticStuff@@A)
Кажется, невозможно инициализировать статические атрибуты неинтегрирующих типов, не вынеся какой-то код за пределы определения класса (CPP).
Для такой компиляции можно использовать "статический метод со статической локальной переменной внутри". Что-то вроде этого:
class Elsewhere
{
public:
static StaticStuff& GetStaticStuff()
{
static StaticStuff staticStuff; // constructor runs once, single instance
return staticStuff;
}
};
А еще можно передавать аргументы в конструктор или инициализировать его конкретными значениями, он очень гибкий, мощный и простой в реализации... Единственное, что у вас есть статический метод, содержащий статическую переменную, а не статический атрибут... синтаксис немного меняется, но все равно он полезен. Надеюсь, это кому-нибудь пригодится,
Уго Гонсалес Кастро.