문제에 대한 해결책을 생각해 냈습니다. 그러나 항상 컴파일러에서 작동하는지 확실하지 않습니다. 첫째, 문제 : 여러 상황에서 동일한 유형이 주어 졌을 때도 다시 사용될 때마다 인스턴스화되는 템플릿 클래스를 사용하는 것이 바람직하다는 것을 알았습니다 (템플릿 클래스에는 함수 호출로 초기화되는 정적 멤버가 있음). 중요한 부작용이 있습니다. 템플릿을 사용할 때마다이 부작용이 발생하기를 바랍니다.) 이 작업을 수행하는 쉬운 방법은 템플릿 추가 정수 매개 변수를 제공하는 것입니다 :C++ 컴파일 시간 프로그램 고유 번호
template<class T, class U, int uniqueify>
class foo
{
...
}
을하지만 지금 당신은 수동으로 foo를 사용할 때마다 당신이 uniqueify 위해에 다른 값을 전달할 수 있는지 확인해야합니다. 순진 솔루션은이 같은 __LINE__
을 사용하는 것입니다
#define MY_MACRO_IMPL(line) foo<line>
#define MY_MACRO MY_MACRO_IMPL(__LINE__)
이 솔루션은 비록 문제가있는 - __LINE__
각 번역 단위에 대한 재설정을 가져옵니다. 따라서 두 개의 번역 단위가 같은 줄에서 템플릿을 사용하면 템플릿은 한 번만 인스턴스화됩니다. 그럴 것 같지 않지만 컴파일러 오류를 디버그하는 것이 얼마나 어려운지 상상해보십시오. 비슷하게 당신은 어떤 식 으로든 파라미터로 __DATE__
을 사용할 수 있습니다. 그러나 초 정밀도를 가지고 있으며 컴파일이 시작될 때가 아니라, 그 라인에 도달 할 때가 아닙니다. 따라서 병렬 버전의 make를 사용한다면 두 개의 번역이 가능합니다. 같은 단위의 __DATE__
.
또 다른 해결책은 특정 비표준 매크로 __COUNTER__
을 사용하는 컴파일러가 있으며 0을 시작하고 사용할 때마다 증가한다는 것입니다. 그러나 동일한 문제가 발생합니다. 전처리 기가 호출 될 때마다 재설정되므로 각 번역 단위가 재설정됩니다.
#define MY_MACRO_IMPL(file, line) foo<T, U, file, line>
#define MY_MACRO MY_MACRO_IMPL(T, U, __FILE__, __LINE__)
그러나 외부 연결이 없기 때문에 당신은 표준에 따라 템플릿 매개 변수로 문자 리터럴을 전달할 수 없습니다 :
또 다른 해결책은 함께 __FILE__
및 __LINE__
을 사용하는 것입니다.
__FILE__
에 파일의 절대 경로가 포함되어 있거나 파일 자체의 이름이 표준에 정의되어 있지 않아도 다른 폴더에 동일한 이름의 파일이 두 개있는 경우 단절. 그래서 내 해결책은 다음과 같습니다.
#ifndef toast_unique_id_hpp_INCLUDED
#define toast_unique_id_hpp_INCLUDED
namespace {
namespace toast {
namespace detail {
template<int i>
struct translation_unit_unique {
static int globally_unique_var;
};
template<int i>
int translation_unit_unique<i>::globally_unique_var;
}
}
}
#define TOAST_UNIQUE_ID_IMPL(line) &toast::detail::translation_unit_unique<line>::globally_unique_var
#define TOAST_UNIQUE_ID TOAST_UNIQUE_ID_IMPL(__LINE__)
#endif
왜이 사용법은 사용 예제가 없으면 처음에는 개요가 명확하지 않습니다. 내가 가진 핵심적인 통찰력은 글로벌 변수 또는 정적 멤버 변수를 만들 때마다 해당 변수의 주소 형태로 프로그램 전체 고유 번호를 생성한다는 것입니다. 그래서 이것은 컴파일 타임에 사용할 수있는 고유 번호를줍니다. __LINE__
은 동일한 번역 단위 내에서 충돌을 일으키지 않으며 외부 익명의 네임 스페이스는 변수가 다른 인스턴스 (즉, 다른 주소를 갖게 함)에서 번역 단위를 통과하도록합니다.
사용 예제 : 같은 템플릿에도 불구하고
#include <toast/unique_id.hpp>
...
typedef MY_MACRO unique_var;
typedef MY_MACRO unique_var2;
unique_var::value = 3;
unique_var2::value = 4;
std::cout << unique_var::value << unique_var2::value;
, 더 차별화 된 매개 변수를 제공하지 않는 사용자는 unique_var
및 unique_var2
는 별개 :
template<int* unique_id>
struct special_var
{
static int value;
}
template<int* unique_id>
int special_var<unique_id>::value = someSideEffect();
#define MY_MACRO_IMPL(unique_id) special_var<unique_id>
#define MY_MACRO MY_MACRO_IMPL(TOAST_UNIQUE_ID)
그리고 foo.cpp에이된다.
나는 컴파일 타임에 실제로 사용할 수있는 익명 네임 스페이스의 변수 주소가 대부분 걱정된다. 기술적으로 익명의 네임 스페이스는 내부 연결을 선언하는 것과 같으며 템플릿 매개 변수는 내부 연결을 가질 수 없습니다. 그러나 표준에서 익명의 네임 스페이스를 처리하는 방법은 변수가 프로그램 전체의 고유 한 이름을 가진 네임 스페이스의 일부로 선언 된 것과 같습니다. 기술적으로는 은이 일반적으로 생각하지는 않지만 외부 연결을 사용합니다. 그것의 그것 같이. 표준이 제 편이라고 생각합니다. 그러나 확실하지 않습니다.
나는이 유용 할 이유을 설명하는 가장 좋은 일을 한 경우 모르겠지만이 토론을 위해서, 그것은, 내가 맹세)
조셉은 이미 '__FILE__'을 고려했지만 문자열 리터럴은 내부 링크가 있고 매크로는 반드시 전체 경로를 포함하지는 않으므로 거부합니다. 충분히 독특해야한다. 그래서, 그 우려 중 어느 것도 유효하지 않다고 말하고 있습니까? –
그래, 실제로 __FILE__을 사용하려고하면 GCC는 적어도 그것을 거부 할 것입니다. 필자는 컴파일러를 따르는 모든 표준이 가능할 것이라고 생각하지만, MSVC와 같은 다른 대중적인 컴파일러가이 점에 부합하는 표준인지 여부는 알 수 없습니다. –
아마도 C++ 11에서 사용자 정의 리터럴 및 constexpr 생성자를 사용하여이 작업을 수행 할 수는 있지만 아직 시도하지 않았습니다. –