// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause // .NAME TestCxxFeatures // .SECTION Description // Provides a reference for the set of C++ features that can be used // by VTK. //------------------------------------------------------------------------------ /* Check for known compilers. */ #if defined(__HP_aCC) #define VTK_CXX_ACC #endif #if defined(__SUNPRO_CC) #define VTK_CXX_SUNPRO #endif //------------------------------------------------------------------------------ /* Check for known compiler limitations. */ // Assume standard behavior if symbol is not already defined. #if !defined(VTK_TYPENAME) #define VTK_TYPENAME typename #endif // Assume standard behavior if symbol is not already defined. #if !defined(VTK_CLASS_TEMPLATE_SPECIALIZATION) #define VTK_CLASS_TEMPLATE_SPECIALIZATION template <> #endif //------------------------------------------------------------------------------ #include "vtkStringFormatter.h" #include "vtkSystemIncludes.h" //------------------------------------------------------------------------------ /* Test inclusion of typeinfo header. */ #include //------------------------------------------------------------------------------ /* Test nested classes defined outside. */ class NestedTestOuter { public: NestedTestOuter(); ~NestedTestOuter(); private: class NestedTestInner; NestedTestInner* Inner; }; class NestedTestOuter::NestedTestInner { public: NestedTestInner() {} ~NestedTestInner() {} }; NestedTestOuter::NestedTestOuter() { this->Inner = new NestedTestInner; } NestedTestOuter::~NestedTestOuter() { delete this->Inner; } //------------------------------------------------------------------------------ /* Test full template specialization of functions. */ template int FullySpecializedFunction(T*) { return 0; } template <> int FullySpecializedFunction(int*) { return 1; } int TestFullySpecializedFunction() { int result = 1; int should_be_0 = FullySpecializedFunction(static_cast(0)); if (should_be_0 != 0) { std::cerr << "FullySpecializedFunction() returned " << should_be_0 << ", not 0.\n"; result = 0; } int should_be_1 = FullySpecializedFunction(static_cast(0)); if (should_be_1 != 1) { std::cerr << "FullySpecializedFunction(int*) returned " << should_be_1 << ", not 1.\n"; result = 0; } return result; } //------------------------------------------------------------------------------ /* Test member template of non-template. */ class NonTemplate { void* Pointer; public: template void Set(T* t) { this->Pointer = t; } template void Get(T*& t) { t = static_cast(this->Pointer); } }; int TestNonTemplateMemberTemplate() { int x = 123; int* px = 0; NonTemplate nt; nt.Set(&x); nt.Get(px); return (*px == 123); } //------------------------------------------------------------------------------ /* Test member template of template. */ template class OuterTemplate { T* Pointer; public: template void Set(U* u) { this->Pointer = u; } template void Get(U*& u) { u = static_cast(this->Pointer); } }; int TestTemplateMemberTemplate() { int x = 123; int* px = 0; OuterTemplate nt; nt.Set(&x); nt.Get(px); return (*px == 123); } //------------------------------------------------------------------------------ /* Test full template specialization of classes. */ template struct FullySpecializedClass { static int Method() { return 0; } typedef T Type; }; VTK_CLASS_TEMPLATE_SPECIALIZATION struct FullySpecializedClass { static int Method() { return 1; } typedef int Type; }; template int TestFullySpecializedClassTrait(T*) { typedef VTK_TYPENAME FullySpecializedClass::Type Type; if (static_cast(3.1) == 3.1) { return 0; } return 1; } int TestFullySpecializedClass() { int result = 1; int should_be_0 = FullySpecializedClass::Method(); if (should_be_0 != 0) { std::cerr << "FullySpecializedClass::Method() returned " << should_be_0 << ", not 0.\n"; result = 0; } int should_be_1 = FullySpecializedClass::Method(); if (should_be_1 != 1) { std::cerr << "FullySpecializedClass::Method() returned " << should_be_1 << ", not 1.\n"; result = 0; } if (!TestFullySpecializedClassTrait(static_cast(0))) { std::cerr << "Trait lookup of float didn't produce int."; result = 0; } return result; } //------------------------------------------------------------------------------ /* Test if(int x = f()) style scoping. */ int TestIfScopeHelper(int i) { int result = 1; if (int x = i) { if (x != i) { std::cerr << "TestIfScope: x != " << i << "\n"; result = 0; } } else { if (x != i) { std::cerr << "TestIfScope: x != " << i << "\n"; result = 0; } } int x = result; return x; } int TestIfScope() { int result = 1; if (!TestIfScopeHelper(1)) { result = 0; } if (!TestIfScopeHelper(0)) { result = 0; } return result; } //------------------------------------------------------------------------------ /* Test non-type template parameter. */ template struct NonTypeTemplate { static int GetValue() { return I; } }; int TestNonTypeTemplate() { int result = 1; if (NonTypeTemplate<0>::GetValue() != 0) { std::cerr << "NonTypeTemplate<0>::GetValue() != 0\n"; result = 0; } if (NonTypeTemplate<1>::GetValue() != 1) { std::cerr << "NonTypeTemplate<1>::GetValue() != 1\n"; result = 0; } if (NonTypeTemplate<2>::GetValue() != 2) { std::cerr << "NonTypeTemplate<2>::GetValue() != 2\n"; result = 0; } return result; } //------------------------------------------------------------------------------ /* Test mixed type and non-type template arguments in a non-trivial way. */ template int TestMixedTypeTemplateFunction(T (*)[N]) { return N; } int TestMixedTypeTemplate() { int x2[2]; float x3[3]; int result = 1; if (TestMixedTypeTemplateFunction(&x2) != 2) { std::cerr << "TestMixedTypeTemplateFunction(&x2) != 2\n"; result = 0; } if (TestMixedTypeTemplateFunction(&x3) != 3) { std::cerr << "TestMixedTypeTemplateFunction(&x3) != 3\n"; result = 0; } return result; } //------------------------------------------------------------------------------ class SafeBoolIdiomClass { private: struct SafeBoolDummy { void Dummy() {} }; typedef void (SafeBoolDummy::*SafeBool)(); public: SafeBoolIdiomClass(int x) : Value(x) { } operator SafeBool() { return this->Value ? &SafeBoolDummy::Dummy : nullptr; } SafeBool operator!() { return this->Value ? nullptr : &SafeBoolDummy::Dummy; } protected: int Value; }; int TestSafeBoolIdiom() { int result = 1; SafeBoolIdiomClass cTrue(1); SafeBoolIdiomClass cFalse(0); if (cTrue) { } else { std::cerr << "if(cTrue) evaluates to false.\n"; result = 0; } if (!cTrue) { std::cerr << "if(!cTrue) evaluates to true.\n"; result = 0; } if (cFalse) { std::cerr << "if(cFalse) evaluates to true.\n"; result = 0; } if (!cFalse) { } else { std::cerr << "if(!cFalse) evaluates to false.\n"; result = 0; } return result; } //------------------------------------------------------------------------------ /* Test use of exceptions. */ #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4702) /* Unreachable code. */ #endif class TestExceptionUnwind { int* pvalue; public: TestExceptionUnwind(int* p) : pvalue(p) { } ~TestExceptionUnwind() { *pvalue = 1; } void Use() {} }; class ExceptionClass { }; void TestThrowException(int* p) { TestExceptionUnwind unwind(p); unwind.Use(); throw ExceptionClass(); } int TestException() { int value = 0; try { TestThrowException(&value); } catch (ExceptionClass&) { if (value) { return 1; } else { std::cerr << "TestExceptionUnwind object not destroyed!" << std::endl; return 0; } } catch (...) { std::cerr << "ExceptionClass not caught!" << std::endl; return 0; } std::cerr << "No exception caught!" << std::endl; return 0; } #if defined(_MSC_VER) #pragma warning(pop) #endif //------------------------------------------------------------------- // See if the following code works on all platforms #if defined(_MSC_VER) && defined(_DEBUG) /* MSVC debug hook to prevent dialogs when running from DART. */ #include static int TestDriverDebugReport(int type, char* message, int* retVal) { (void)type; (void)retVal; vtk::print(stderr, message); exit(1); } #endif //------------------------------------------------------------------------------ /* Test setlocale */ #include #include int TestSetLocale() { char* oldLocale = strdup(setlocale(LC_NUMERIC, nullptr)); setlocale(LC_NUMERIC, "English"); // restore the local if (oldLocale) { setlocale(LC_NUMERIC, oldLocale); free(oldLocale); return 1; } return 0; } //------------------------------------------------------------------------------ #define DO_TEST(x) \ if (x()) \ { \ std::cout << "Passed: " #x "\n"; \ } \ else \ { \ std::cout << "Failed: " #x "\n"; \ result = 1; \ } int main() { int result = 0; DO_TEST(TestFullySpecializedFunction); DO_TEST(TestNonTemplateMemberTemplate); DO_TEST(TestTemplateMemberTemplate); DO_TEST(TestFullySpecializedClass); DO_TEST(TestIfScope); DO_TEST(TestNonTypeTemplate); DO_TEST(TestMixedTypeTemplate); DO_TEST(TestSafeBoolIdiom); DO_TEST(TestException); DO_TEST(TestSetLocale); #if defined(_MSC_VER) && defined(_DEBUG) // just call the code to shut up a linker warning int retVal = 0; if (result) { // really shouldn't be called unless something else failed // just want to make the compiler think it might get called // all this will be yanked once I see the results of this test TestDriverDebugReport(0, "a temp test", &retVal); } #endif return result; }