Моим любимым решением является использование Zend Framework 2. Он также рассматривает свойства $_SERVER
HTTP_X_FORWARDED_FOR
, HTTP_CLIENT_IP
, REMOTE_ADDR
, но объявляет класс для установки некоторых доверенных прокси и возвращает один IP-адрес, а не массив. Я думаю, что это самое близкое к нему решение:
class RemoteAddress
{
/**
* Whether to use proxy addresses or not.
*
* As default this setting is disabled - IP address is mostly needed to increase
* security. HTTP_* are not reliable since can easily be spoofed. It can be enabled
* just for more flexibility, but if user uses proxy to connect to trusted services
* it's his/her own risk, only reliable field for IP address is $_SERVER['REMOTE_ADDR'].
*
* @var bool
*/
protected $useProxy = false;
/**
* List of trusted proxy IP addresses
*
* @var array
*/
protected $trustedProxies = array();
/**
* HTTP header to introspect for proxies
*
* @var string
*/
protected $proxyHeader = 'HTTP_X_FORWARDED_FOR';
// [...]
/**
* Returns client IP address.
*
* @return string IP address.
*/
public function getIpAddress()
{
$ip = $this->getIpAddressFromProxy();
if ($ip) {
return $ip;
}
// direct IP address
if (isset($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR'];
}
return '';
}
/**
* Attempt to get the IP address for a proxied client
*
* @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2
* @return false|string
*/
protected function getIpAddressFromProxy()
{
if (!$this->useProxy
|| (isset($_SERVER['REMOTE_ADDR']) && !in_array($_SERVER['REMOTE_ADDR'], $this->trustedProxies))
) {
return false;
}
$header = $this->proxyHeader;
if (!isset($_SERVER[$header]) || empty($_SERVER[$header])) {
return false;
}
// Extract IPs
$ips = explode(',', $_SERVER[$header]);
// trim, so we can compare against trusted proxies properly
$ips = array_map('trim', $ips);
// remove trusted proxy IPs
$ips = array_diff($ips, $this->trustedProxies);
// Any left?
if (empty($ips)) {
return false;
}
// Since we've removed any known, trusted proxy servers, the right-most
// address represents the first IP we do not know about -- i.e., we do
// not know if it is a proxy server, or a client. As such, we treat it
// as the originating IP.
// @see http://en.wikipedia.org/wiki/X-Forwarded-For
$ip = array_pop($ips);
return $ip;
}
// [...]
}
Смотрите полный код здесь: https://raw.githubusercontent.com/zendframework/zend-http/master/src /PhpEnvironment/RemoteAddress.php
Вы заявили свою функцию как friend
. Это не член класса. Вы должны удалить Matrix::
из реализации. friend
означает, что указанная функция (которая не является членом класса) может обращаться к частным переменным-членам. Способ реализации функции подобен методу экземпляра для класса Matrix
, который является неправильным.
Предполагая, что мы говорим о перегрузке operator <<
для всех классов, полученных из std::ostream
для обработки класса Matrix
(а не для перегрузки <<
для класса Matrix
), имеет смысл объявить функция перегрузки вне пространства имен Math в заголовке.
Используйте функцию friend только в том случае, если функциональность не может быть достигнута через общедоступные интерфейсы.
Matrix.h
namespace Math {
class Matrix {
//...
};
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);
Обратите внимание, что перегрузка оператора объявляется вне пространства имен.
Matrix.cpp
using namespace Math;
using namespace std;
ostream& operator<< (ostream& os, const Matrix& obj) {
os << obj.getXYZ() << obj.getABC() << '\n';
return os;
}
С другой стороны, если ваша функция перегрузки делает нужно сделать другом, т. е. нуждается в доступе к частным и защищенным членам.
Math.h
namespace Math {
class Matrix {
public:
friend std::ostream& operator<<(std::ostream&, const Matrix&);
};
}
Вам нужно приложить определение функции блоком пространства имен, а не просто using namespace Math;
.
Matrix.cpp
using namespace Math;
using namespace std;
namespace Math {
ostream& operator<<(ostream& os, const Matrix& obj) {
os << obj.XYZ << obj.ABC << '\n';
return os;
}
}
Просто расскажу вам о другой возможности: мне нравится использовать определения друзей для этого:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
[...]
}
};
}
Функция будет автоматически нацелена на окружающее пространство имен Math
(хотя его определение появляется в пределах объем этого класса), но не будет отображаться, если вы не вызываете оператор & lt; & lt; с объектом Matrix, который заставит зависящий от аргумента поиск найти это определение оператора. Иногда это может помочь с неоднозначными вызовами, поскольку оно невидимо для типов аргументов, отличных от Matrix. При написании своего определения вы также можете ссылаться непосредственно на имена, определенные в матрице и на матрицу, без определения имени с некоторым возможным длинным префиксом и предоставления параметров шаблона, таких как Math::Matrix<TypeA, N>
.
Чтобы добавить к ответу Мехридада,
namespace Math
{
class Matrix
{
public:
[...]
}
std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}
В вашей реализации
std::ostream& operator<<(std::ostream& stream,
const Math::Matrix& matrix) {
matrix.print(stream); //assuming you define print for matrix
return stream;
}
В C ++ 14 вы можете использовать следующий шаблон для печати любого объекта, который имеет T :: print (std :: ostream & amp;) const; член.
template<class T>
auto operator<<(std::ostream& os, const T& t) -> decltype(t.print(os), os)
{
t.print(os);
return os;
}
std::ostream&
, так как это тип возврата в любом случае?
– Jean-Michaël Celerier
8 March 2017 в 21:16
operator<<
должен находиться в пространстве именMath
? Кажется, что это должно быть в глобальном пространстве имен. Я согласен с тем, что мой компилятор хочет, чтобы он находился в пространстве именMath
, но это не имеет смысла для меня. – Mark Lakata 1 May 2015 в 21:58