Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有共享私有数据的模板函数_C++_Templates_Static_Private - Fatal编程技术网

C++ 具有共享私有数据的模板函数

C++ 具有共享私有数据的模板函数,c++,templates,static,private,C++,Templates,Static,Private,我在以下情况下寻找“最佳实践”: 一般来说,两个(或多个)非成员函数之间共享私有数据的方法有三种,各有优缺点: // Example 1: using 'static' class // HPP namespace foo { class bar { private: static const char* const s_private; bar(); public: static void s_method0(

我在以下情况下寻找“最佳实践”: 一般来说,两个(或多个)非成员函数之间共享私有数据的方法有三种,各有优缺点:

// Example 1: using 'static' class

// HPP
namespace foo {
    class bar
    {
    private:
        static const char* const s_private;
        bar();

    public:
        static void s_method0();
        static void s_method1();
    }; /* class bar */
} /* namespace foo */

// CPP
namespace foo {
    const char* const bar::s_private = "why do I need to be visible in HPP?";

    void bar::s_method0() { std::cout << "s_method0 said: " << s_private << std::endl; }
    void bar::s_method1() { std::cout << "s_method1 said: " << s_private << std::endl; } 
} /* namespace foo */


// Example 2: using unnamed-namespace

// HPP
namespace foo { 
    void bar0(); 
    void bar1();
} /* namespace foo */

// CPP
namespace foo {
    namespace {
        const char* const g_anonymous = "why do I need external linkage?";
    } /* unnamed-namespace */

    void bar0() { std::cout << "bar0 said: " << g_anonymous << std::endl; }
    void bar1() { std::cout << "bar1 said: " << g_anonymous << std::endl; }
} /* namespace foo */


// Example 3: using static keyword in namespace-scope

// HPP
namespace foo { 
    void bar0(); 
    void bar1();
} /* namespace foo */

// CPP
namespace foo {
    static const char* const g_internal = "nobody outside this file can see me and I don't have external linkage";

    void bar0() { std::cout << "bar0 said: " << g_internal << std::endl; }
    void bar1() { std::cout << "bar1 said: " << g_internal << std::endl; }
} /* namespace foo */
//示例1:使用“static”类
//水电站
名称空间foo{
分类栏
{
私人:
静态常量char*常量s_private;
bar();
公众:
静态void s_method0();
静态void s_method1();
}/*类栏*/
}/*名称空间foo*/
//CPP
名称空间foo{
const char*const bar::s_private=“为什么我需要在HPP中可见?”;
void bar::s_method0(){std::cout那怎么办

namespace foo {
    namespace detail {
        class shared 
        { 
            template<typename> friend void bar0();
            template<typename> friend void bar1();

            static const char* const m_private; 
        }; /* class shared */
    } /* namespace detail */

    template<typename T> void bar0() { std::cout << "bar0 said: " << detail::shared::m_private << std::endl; }
    template<typename T> void bar1() { std::cout << "bar1 said: " << detail::shared::m_private << std::endl; }
} /* namespace foo */
名称空间foo{
名称空间详细信息{
类共享
{ 
模板0();
模板1();
静态常量char*常量m_private;
};/*类共享*/
}/*名称空间详细信息*/
模板void bar0(){std::cout这是怎么回事

namespace foo {
    namespace detail {
        class shared 
        { 
            template<typename> friend void bar0();
            template<typename> friend void bar1();

            static const char* const m_private; 
        }; /* class shared */
    } /* namespace detail */

    template<typename T> void bar0() { std::cout << "bar0 said: " << detail::shared::m_private << std::endl; }
    template<typename T> void bar1() { std::cout << "bar1 said: " << detail::shared::m_private << std::endl; }
} /* namespace foo */
名称空间foo{
名称空间详细信息{
类共享
{ 
模板0();
模板1();
静态常量char*常量m_private;
};/*类共享*/
}/*名称空间详细信息*/

template void bar0(){std::cout如果我理解正确,您的抱怨/担忧是,与模板不同,对于非模板,可以在CPP中定义函数体,而不是标头,在这种情况下,它们可以访问“不可见”的非类静态对于外部世界,包括在标题中定义的成员函数。这都是真的

但是,请记住,在CPP中定义其他成员函数也没有什么可以阻止的,在这种情况下,它们同样能够访问静态数据。因此,事实上,情况没有什么不同。您的投诉基于错误的二分法


如果你真的不想阻止任何事情,除了
s_method0()
s_method1()
访问
s_private
,然后你必须将它们都放在一个专用类中。就这么简单。即使是非模板也是如此。

如果我理解正确,你的抱怨/担心是,与模板不同,非模板可以在CPP中定义函数体,而不是标题在这种情况下,他们可以访问外部世界“看不见”的非类静态,包括头中定义的成员函数

但是,请记住,在CPP中定义其他成员函数也没有什么可以阻止的,在这种情况下,它们同样能够访问静态数据。因此,事实上,情况没有什么不同。您的投诉基于错误的二分法


如果你真的不想阻止任何事情,除了
s_method0()
s_method1()
访问
s_private
,然后你必须将它们都放在一个专用类中。就这么简单。即使是非模板也是如此。

我已经使用了不同的技术。我的想法是,在头文件中使用未命名的名称空间,将“共享”类“标记”为“仅头文件”。当然,因为事实上,他们不包含公众成员,你无论如何也不能用它来制造令人讨厌的事情。但我认为这会更接近你的意图

但我错了!考虑到这一点后,我感到羞愧。它在逻辑上非常简单。这个示例显示了它的问题所在(为了清晰起见,整个代码):

这意味着:如果你正在寻找未定义的行为,那么你就在这里。 换句话说:基于上面的解释:不要在头文件中使用未命名的名称空间来封装私有共享数据

最后一个问题是,“解决方案是什么?” 如果您不想使用“静态”(实用程序)类,您应该更喜欢我第一次发布的解决方案(仅更改代码):

//header0.hpp
// ...
名称空间ns{
// ...  
名称空间详细信息{
班长0{/*…*/};
}/*名称空间详细信息*/

模板无效标头0_func0(){std::cout我曾经尝试过不同的技术。我的想法是,在头文件中使用未命名的名称空间,将“共享”类“标记”为“仅头文件”。当然,由于它们不包含公共成员,所以无论如何也不能用它来制造麻烦。但我认为这更接近于目的

但我错了!考虑到这一点后,我感到羞愧。它在逻辑上非常简单。这个示例显示了它的问题所在(为了清晰起见,整个代码):

这意味着:如果你正在寻找未定义的行为,那么你就在这里。 换句话说:基于上面的解释:不要在头文件中使用未命名的名称空间来封装私有共享数据

最后一个问题是,“解决方案是什么?” 如果您不想使用“静态”(实用程序)类,您应该更喜欢我第一次发布的解决方案(仅更改代码):

//header0.hpp
// ...
名称空间ns{
// ...  
名称空间详细信息{
班长0{/*…*/};
}/*名称空间详细信息*/

模板void header0_func0(){std::cout这是一个在模板中经常出现的问题,有点遗憾

但我可以建议你在这里工作吗

事实是,无论你看Loki代码(由Andrei Alexandrescu编写)还是Boost代码(臭名昭著的David Abrahams),都没有人真正愿意提供更好的隐私

相反,他们仅仅依赖于约定,使用
私有
名称空间(Loki)或
细节
名称空间(Boost,有时使用更长更具描述性的名称以防止冲突)

这很烦人,但在实践中你能做的并不多……尽管我实际上对你的具体问题有一个解决方案;)

//邪恶的解决方案!
#ifdef MY_SUPER_宏
#错误“我的超级宏已被定义”
namespace foo {
    template<typename T> void bar0();
    template<typename T> void bar1();
    template<typename T> void bar2();
    template<typename T> void bar3();


    namespace {
        class shared0 
        { 
            template<typename> friend void foo::bar0();
            template<typename> friend void foo::bar1();

            static const char* const m_private0; 
        }; /* class shared0 */

        class shared1
        { 
            template<typename> friend void foo::bar2();
            template<typename> friend void foo::bar3();

            static const char* const m_private1;    
        }; /* class shared1 */
    } /* unnamed */


    template<typename T> void bar0() { std::cout << "bar0 said: " << shared0::m_private0 << std::endl; }
    template<typename T> void bar1() { std::cout << "bar1 said: " << shared0::m_private0 << std::endl; }

    template<typename T> void bar2() { std::cout << "bar0 said: " << shared1::m_private1 << std::endl; }
    template<typename T> void bar3() { std::cout << "bar1 said: " << shared1::m_private1 << std::endl; }
} /* namespace foo */
// header0.hpp
#ifndef HPP_HEADER0_INCLUDED
#define HPP_HEADER0_INCLUDED

#include <iostream>
#include <string>

namespace ns {
    template<typename T> void header0_func0();
    template<typename T> void header0_func1();

    namespace {
        class header0
        {
            template<typename> friend void ns::header0_func0();
            template<typename> friend void ns::header0_func1();

            static std::string s_private;
        }; /* class header0 */
    } /* unnamed */

    template<typename T> void header0_func0() { std::cout << "header0_func0: " << header0::s_private << std::endl; }
    template<typename T> void header0_func1() { std::cout << "header0_func1: " << header0::s_private << std::endl; }
} /* namespace ns */

#endif /* HPP_HEADER0_INCLUDED */ 


// header1.hpp
#ifndef HPP_HEADER1_INCLUDED
#define HPP_HEADER1_INCLUDED

#include <iostream>
#include <string>

namespace ns {
    template<typename T> void header1_func0();
    template<typename T> void header1_func1();

    namespace {
        class header1
        {
            template<typename> friend void ns::header1_func0();
            template<typename> friend void ns::header1_func1();

            static std::string s_private;
        }; /* class header1 */
    } /* unnamed */

    template<typename T> void header1_func0() { std::cout << "header1_func0: " << header1::s_private << std::endl; }
    template<typename T> void header1_func1() { std::cout << "header1_func0: " << header1::s_private << std::endl; }
} /* namespace ns */

#endif /* HPP_HEADER1_INCLUDED */


// source.cpp
#include "header0.hpp"
#include "header1.hpp"

std::string ns::header0::s_private = "header0 private data definition by source.cpp",
            ns::header1::s_private = "header1 private data definition by source.cpp";

namespace {
    // hide private class
    class source
    {
        source();
        ~source();

        static source s_instance;
    };

    source::source() { 
        std::cout << "source.cpp:\n";
        ns::header0_func0<int>();
        ns::header0_func1<int>();
        ns::header1_func0<int>();
        ns::header1_func1<int>();
        std::cout << '\n';
    }

    source::~source() { }
    source source::s_instance;
} /* unnamed */
// main.cpp
#include "header0.hpp"
#include "header1.hpp"

int main()
{   
    std::cout << "main.cpp:\n";
    ns::header0_func0<int>();
    ns::header0_func1<int>();
    ns::header1_func0<int>();
    ns::header1_func1<int>();
    std::cout << '\n';

    return 0;
}
// main.cpp
#include "header0.hpp"
#include "header1.hpp"

std::string ns::header0::s_private = "header0 private data definition by main.cpp",
            ns::header1::s_private = "header1 private data definition by main.cpp";

int main()
{   
    std::cout << "main.cpp:\n";
    ns::header0_func0<int>();
    ns::header0_func1<int>();
    ns::header1_func0<int>();
    ns::header1_func1<int>();
    std::cout << '\n';

    return 0;
}
source.cpp:
header0_func0: header0 private data definition by source.cpp
header0_func1: header0 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp

main.cpp:
header0_func0: header0 private data definition by source.cpp
header0_func1: header0 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
// header0.hpp
// ...
namespace ns {
    // ...  
    namespace detail { 
        class header0 { /*...*/ };
    } /* namespace detail */

    template<typename T> void header0_func0() { std::cout << "header0_func0: " << detail::header0::s_private << std::endl; }
    template<typename T> void header0_func1() { std::cout << "header0_func1: " << detail::header0::s_private << std::endl; }
} /* namespace ns */
// ...

// header1.hpp
// ...
namespace ns {
    // ...  
    namespace detail { 
        class header1 { /*...*/ };
    } /* namespace detail */

    template<typename T> void header0_func0() { std::cout << "header0_func0: " << detail::header1::s_private << std::endl; }
    template<typename T> void header0_func1() { std::cout << "header0_func1: " << detail::header1::s_private << std::endl; }
} /* namespace ns */
// ...

// source.cpp
// ...
std::string ns::detail::header0::s_private = "header0 private data definition by source.cpp",
            ns::detail::header1::s_private = "header1 private data definition by source.cpp";
// ...
// Evil solution!

#ifdef MY_SUPER_MACRO
#  error "MY_SUPER_MACRO is already defined!"
#endif

#define MY_SUPER_MACRO "Some string"

template <typename T> void foo() { std::cout << "foo - " MY_SUPER_MACRO "\n"; }
template <typename T> void bar() { std::cout << "bar - " MY_SUPER_MACRO "\n"; }

#undef MY_SUPER_MACRO