Другое событие NullPointerException
возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals
для гарантированного непустого объекта.
Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null
.
Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Единственный способ ограничить шаблон состоит в том, чтобы сделать его так, чтобы это использовало что-то от типов, которые Вы хотите, что другие типы не имеют.
Так, Вы создаете с интервалом, используете + и + =, вызываете конструктора копии, и т.д.
Какой-либо тип, который имеет все их, будет работать с Вашей функцией - так, если я создам новый тип, который имеет эти функции, Ваша функция будет работать над ним - который является большим, не так ли?
, Если Вы хотите ограничить его больше, используйте больше функций, которые только определяются для типа, который Вы хотите.
Другой способ реализовать это путем создания шаблона черт - что-то вроде этого
template<class T>
SumTraits
{
public:
const static bool canUseSum = false;
}
, И затем специализируйте его для классов, Вы хотите быть в порядке:
template<>
class SumTraits<int>
{
public:
const static bool canUseSum = true;
};
Тогда в Вашем коде, можно записать
if (!SumTraits<T>::canUseSum) {
// throw something here
}
редактирование: как упомянуто в комментариях, можно использовать BOOST_STATIC_ASSERT для создания его проверкой времени компиляции вместо во время выполнения
Это возможно при помощи SFINAE, и сделанный легче при помощи помощников или от Повышения или от C++ 11
Повышение:
#include <vector>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
template<typename T>
typename boost::enable_if<typename boost::is_arithmetic<T>::type, T>::type
sum(const std::vector<T>& vec)
{
typedef typename std::vector<T>::size_type size_type;
T result;
size_type size = vec.size();
for(size_type i = 0; i < size; i++)
{
result += vec[i];
}
return result;
}
C++ 11:
#include <vector>
#include <type_traits>
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
sum(const std::vector<T>& vec)
{
T result;
for (auto item : vec)
result += item;
return result;
}
Можно сделать что-то вроде этого:
template <class T>
class NumbersOnly
{
private:
void ValidateType( int &i ) const {}
void ValidateType( long &l ) const {}
void ValidateType( double &d ) const {}
void ValidateType( float &f ) const {}
public:
NumbersOnly()
{
T valid;
ValidateType( valid );
};
};
Вы получите ошибку, при попытке создать NumbersOnly, который не имеет перегрузки ValidateType:
NumbersOnly<int> justFine;
NumbersOnly<SomeClass> noDeal;
Именно так Вы делаете это.
Комментарий шаблонная специализация для двойного, например.. и это не позволит Вам вызывать ту функцию с дважды как параметр. Прием - то, что, при попытке назвать сумму с типом, который не является среди специализаций IsNumber
, тогда универсальную реализацию называют, и та реализация делает что-то не позволенным (назовите частного конструктора).
сообщение об ошибке не интуитивно, если Вы не переименовываете IsNumber
класс к чему-то, что походит на сообщение об ошибке.
#include <vector>
#include <iostream>
using namespace std;
template<class T> struct IsNumber{
private:
IsNumber(){}
};
template<> struct IsNumber<float>{
IsNumber(){};
};
template<> struct IsNumber<double>{
IsNumber(){};
};
template<> struct IsNumber<int>{
IsNumber(){};
};
template <typename T>
T sum(vector<T>& a)
{
IsNumber<T> test;
T result = 0;
int size = a.size();
for(int i = 0; i < size; i++)
{
result += a[i];
}
return result;
}
int main()
{
vector<int> int_values;
int_values.push_back(2);
int_values.push_back(3);
cout << "Integer: " << sum(int_values) << endl;
vector<double> double_values;
double_values.push_back(1.5);
double_values.push_back(2.1);
cout << "Double: " << sum(double_values);
return 0;
}
Почему Вы хотели бы ограничить типы в этом случае? Шаблоны позволяют "статический утиный ввод", таким образом, что-либо позволенное тем, что Ваш sum
в этом случае должна быть позволена функция. А именно, единственная операция, требуемая T
, является добавлять-присвоением и инициализацией 0, таким образом, любой тип, который поддерживает те две операции, работал бы. Это - красота шаблонов.
(При изменении инициализатора на T result = T();
и т.п., тогда это работало бы и на числа и на строки, также.)
Вы могли изучить черты типа (используйте повышение, ожидайте C++ 0x или создайте Ваше собственное).
я нашел следующий Google: http://artins.org/ben/programming/mactechgrp-artin-cpp-type-traits.pdf
Действительно, нет никакой потребности сделать его более строгим. Взгляните на строковую версию (использующий стиль конструктора по умолчанию, рекомендуемый Chris Jester-Young) здесь ...
Заботятся также для переполнения - Вам, возможно, понадобился бы больший тип, чтобы содержать промежуточные результаты (или произвести результаты). Добро пожаловать в область метапрограммирования, тогда:)