Preventing multiple instantiations of a templated function

Discussion in 'C++' started by Dave Rahardja, Jan 20, 2007.

  1. Hi all,

    Is it possible to prevent _at compile or link time_ the mulitple instantiation
    of a templated function? In other words, if there exists a function

    template <typename T> void fn();

    I want to prevent the user from doing this:

    int main()
    {
    fn<int>();
    fn<double>(); // <-- should cause compile time or link time error
    }

    It matters that there is only one instance of the function in the entire
    program. It doesn't matter which type becomes instantiated, but there cannot
    be two references to the function with two different type parameters.

    If this is possible, then is there a way to do this for _any_ templated
    entity?

    -dr
    Dave Rahardja, Jan 20, 2007
    #1
    1. Advertising

  2. Dave Rahardja

    Ian Collins Guest

    Dave Rahardja wrote:
    > Hi all,
    >
    > Is it possible to prevent _at compile or link time_ the mulitple instantiation
    > of a templated function? In other words, if there exists a function
    >
    > template <typename T> void fn();
    >
    > I want to prevent the user from doing this:
    >
    > int main()
    > {
    > fn<int>();
    > fn<double>(); // <-- should cause compile time or link time error
    > }
    >
    > It matters that there is only one instance of the function in the entire
    > program. It doesn't matter which type becomes instantiated, but there cannot
    > be two references to the function with two different type parameters.
    >

    Each instance of the function template is a unique function, so the
    answer is probably no.

    Why do you want to do this?

    --
    Ian Collins.
    Ian Collins, Jan 20, 2007
    #2
    1. Advertising

  3. Dave Rahardja

    IR Guest

    Ian Collins wrote:

    > Dave Rahardja wrote:
    >> I want to prevent the user from doing this:
    >>
    >> int main()
    >> {
    >> fn<int>();
    >> fn<double>(); // <-- should cause compile time or link time
    >> error
    >> }
    >>
    >> It matters that there is only one instance of the function in the
    >> entire program. It doesn't matter which type becomes
    >> instantiated, but there cannot be two references to the function
    >> with two different type parameters.
    >>

    > Each instance of the function template is a unique function, so
    > the answer is probably no.


    I'd add that even if you could enforce a single *specialization* of
    the template in your whole program, there are chances (depending on
    the quality of your compiler) that multiples *instances* of the
    specialization could be generated.


    Cheers,
    --
    IR
    IR, Jan 20, 2007
    #3
  4. On Sun, 21 Jan 2007 09:14:12 +1300, Ian Collins <> wrote:

    >Dave Rahardja wrote:
    >> Hi all,
    >>
    >> Is it possible to prevent _at compile or link time_ the mulitple instantiation
    >> of a templated function? In other words, if there exists a function
    >>
    >> template <typename T> void fn();
    >>
    >> I want to prevent the user from doing this:
    >>
    >> int main()
    >> {
    >> fn<int>();
    >> fn<double>(); // <-- should cause compile time or link time error
    >> }
    >>
    >> It matters that there is only one instance of the function in the entire
    >> program. It doesn't matter which type becomes instantiated, but there cannot
    >> be two references to the function with two different type parameters.
    >>

    >Each instance of the function template is a unique function, so the
    >answer is probably no.
    >
    >Why do you want to do this?


    I have a set of accessors in a library of this form:


    template <class ReservationPolicy>
    class Resource: private ReservationPolicy
    { // ...
    };

    template <class ReservationPolicy>
    Resource& getResource()
    {
    static Resource<ReservationPolicy> resource;
    return resource;
    }


    It's a simplistic Singleton accessor for a Resource that is implemented in
    terms of some ReservationPolicy.

    Problem is, it's an error to have the same resource accessed via a multitude
    of ReservationPolicy's, because the accessor provides access to a single
    underlying resource. A decision must be made at program design time as to what
    ReservationPolicy that one resource is supposed to use. Once that decision is
    made, it is an error to call a different instance of getResource().

    I can prevent the problem at _runtime_ by:

    #include <cassert>

    // The resource.
    template <class ReservationPolicy>
    class Resource: private ReservationPolicy
    { /* ... */ };

    struct ResourceTag {};

    // Helper class that helps enforce a one-instantiation rule.
    template <typename T>
    class OneInstance
    {
    public:
    OneInstance()
    { assert(++instanceCount == 1); }

    private:
    static int instanceCount;
    };

    template <typename T> int OneInstance<T>::instanceCount = 0;

    // Accessor function. Only one instance of this function can be
    // called without generating a runtime error.
    template <ReservationPolicy>
    Resource& getResource()
    {
    static OneInstance<ResourceTag> oneInstance;
    static Resource<ReservationPolicy> resource;
    return resource;
    }

    // Reservation policies
    class Policy0 { /* ... */ };
    class Policy1 { /* ... */ };

    int main()
    {
    fn<Policy0>(); // OK
    fn<Policy0>(); // OK
    fn<Policy1>(); // Runtime assertion
    }


    But I'd like to know if I can prevent this problem at _compile or link_ time.

    -dr
    Dave Rahardja, Jan 20, 2007
    #4
  5. Dave Rahardja

    Jim Langston Guest

    "Dave Rahardja" <> wrote in message
    news:...
    > Hi all,
    >
    > Is it possible to prevent _at compile or link time_ the mulitple
    > instantiation
    > of a templated function? In other words, if there exists a function
    >
    > template <typename T> void fn();
    >
    > I want to prevent the user from doing this:
    >
    > int main()
    > {
    > fn<int>();
    > fn<double>(); // <-- should cause compile time or link time error
    > }
    >
    > It matters that there is only one instance of the function in the entire
    > program. It doesn't matter which type becomes instantiated, but there
    > cannot
    > be two references to the function with two different type parameters.
    >
    > If this is possible, then is there a way to do this for _any_ templated
    > entity?
    >
    > -dr


    I can think of a way to do it using a global and a static.

    #include <iostream>
    #include <string>

    bool fn_created = false;

    template <typename T> void fn( T Val )
    {
    static FirstTime = true;
    if ( FirstTime )
    {
    if ( fn_created )
    throw "Function already created using diff type!";
    fn_created = true;
    FirstTime = false;
    }
    std::cout << "Value is " << Val << "\n";

    }

    int main()
    {
    fn<int>( 10 );
    fn<int>( 20 );
    fn<int>( 30 );
    // Uncommenting out following line will cause run time throw
    // fn<double>( 40.0 );

    std::string wait;
    std::getline( std::cin, wait );
    }
    Jim Langston, Jan 21, 2007
    #5
  6. Dave Rahardja

    Jim Langston Guest

    "Jim Langston" <> wrote in message
    news:w0Bsh.540$...
    > "Dave Rahardja" <> wrote in message
    > news:...
    >> Hi all,
    >>
    >> Is it possible to prevent _at compile or link time_ the mulitple
    >> instantiation
    >> of a templated function? In other words, if there exists a function
    >>
    >> template <typename T> void fn();
    >>
    >> I want to prevent the user from doing this:
    >>
    >> int main()
    >> {
    >> fn<int>();
    >> fn<double>(); // <-- should cause compile time or link time error
    >> }
    >>
    >> It matters that there is only one instance of the function in the entire
    >> program. It doesn't matter which type becomes instantiated, but there
    >> cannot
    >> be two references to the function with two different type parameters.
    >>
    >> If this is possible, then is there a way to do this for _any_ templated
    >> entity?
    >>
    >> -dr

    >
    > I can think of a way to do it using a global and a static.
    >
    > #include <iostream>
    > #include <string>
    >
    > bool fn_created = false;
    >
    > template <typename T> void fn( T Val )
    > {
    > static FirstTime = true;
    > if ( FirstTime )
    > {
    > if ( fn_created )
    > throw "Function already created using diff type!";
    > fn_created = true;
    > FirstTime = false;
    > }
    > std::cout << "Value is " << Val << "\n";
    >
    > }
    >
    > int main()
    > {
    > fn<int>( 10 );
    > fn<int>( 20 );
    > fn<int>( 30 );
    > // Uncommenting out following line will cause run time throw
    > // fn<double>( 40.0 );
    >
    > std::string wait;
    > std::getline( std::cin, wait );
    > }


    Sorry, ignore this. This is runtime. I didn't fully understand your
    question until I reread it.
    Jim Langston, Jan 21, 2007
    #6
  7. * Dave Rahardja:
    >
    > Is it possible to prevent _at compile or link time_ the mulitple instantiation
    > of a templated function? In other words, if there exists a function
    >
    > template <typename T> void fn();
    >
    > I want to prevent the user from doing this:
    >
    > int main()
    > {
    > fn<int>();
    > fn<double>(); // <-- should cause compile time or link time error
    > }
    >
    > It matters that there is only one instance of the function in the entire
    > program. It doesn't matter which type becomes instantiated, but there cannot
    > be two references to the function with two different type parameters.


    With 20-20 hindsight this might seem trivial:

    template< typename T >
    void fn()
    {
    COMPILE_TIME_ASSERT( SameType<T, ::FnType>::yes );
    // ...
    }

    where ::FnType must be defined by the client code.

    It might be possible to circumvent the restriction by using an anonymous
    namespace (say), but then anything can be circumvented -- I gather the
    problem is to prevent inadvertent multiple specializations.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Jan 21, 2007
    #7
  8. On Sun, 21 Jan 2007 04:43:46 +0100, "Alf P. Steinbach" <> wrote:

    >* Dave Rahardja:
    >>
    >> Is it possible to prevent _at compile or link time_ the mulitple instantiation
    >> of a templated function? In other words, if there exists a function
    >>
    >> template <typename T> void fn();
    >>
    >> I want to prevent the user from doing this:
    >>
    >> int main()
    >> {
    >> fn<int>();
    >> fn<double>(); // <-- should cause compile time or link time error
    >> }
    >>
    >> It matters that there is only one instance of the function in the entire
    >> program. It doesn't matter which type becomes instantiated, but there cannot
    >> be two references to the function with two different type parameters.

    >
    >With 20-20 hindsight this might seem trivial:
    >
    > template< typename T >
    > void fn()
    > {
    > COMPILE_TIME_ASSERT( SameType<T, ::FnType>::yes );
    > // ...
    > }
    >
    >where ::FnType must be defined by the client code.
    >
    >It might be possible to circumvent the restriction by using an anonymous
    >namespace (say), but then anything can be circumvented -- I gather the
    >problem is to prevent inadvertent multiple specializations.


    I don't understand how your solution works. Could you elaborate on what
    SameType<...> does?
    Dave Rahardja, Jan 21, 2007
    #8
  9. * Dave Rahardja:
    > On Sun, 21 Jan 2007 04:43:46 +0100, "Alf P. Steinbach" <> wrote:
    >
    >> * Dave Rahardja:
    >>> Is it possible to prevent _at compile or link time_ the mulitple instantiation
    >>> of a templated function? In other words, if there exists a function
    >>>
    >>> template <typename T> void fn();
    >>>
    >>> I want to prevent the user from doing this:
    >>>
    >>> int main()
    >>> {
    >>> fn<int>();
    >>> fn<double>(); // <-- should cause compile time or link time error
    >>> }
    >>>
    >>> It matters that there is only one instance of the function in the entire
    >>> program. It doesn't matter which type becomes instantiated, but there cannot
    >>> be two references to the function with two different type parameters.

    >> With 20-20 hindsight this might seem trivial:
    >>
    >> template< typename T >
    >> void fn()
    >> {
    >> COMPILE_TIME_ASSERT( SameType<T, ::FnType>::yes );
    >> // ...
    >> }
    >>
    >> where ::FnType must be defined by the client code.
    >>
    >> It might be possible to circumvent the restriction by using an anonymous
    >> namespace (say), but then anything can be circumvented -- I gather the
    >> problem is to prevent inadvertent multiple specializations.

    >
    > I don't understand how your solution works. Could you elaborate on what
    > SameType<...> does?


    Checks whether the types are the same. I thought that would be clear.
    But then, I'm not the world's greatest communicator...

    template< typename T, typename U >
    struct SameType { enum { yes = false }; };

    template< typename T >
    struct SameType<T, T> { enum { yes = true }; }

    That leaves COMPILE_TIME_ASSERT and where ::FnType comes from.

    The Boost library has a nice COMPILE_TIME_ASSERT.

    ::FnType must be defined by the client code.

    Since it's at namespace scope (I used the global namespace for purpose
    of illustration) it can't be duplicated if it's a class. And to make
    more sure that it's a class you can let the function refer to a nested
    typedef. The client code's definition might then look like

    struct FnType { typedef double Type; };

    and the function definition as

    template< typename T >
    void fn()
    {
    COMPILE_TIME_ASSERT( SameType<T, ::FnType::Type>::yes );
    // ...
    }

    OK? Well, disclaimer: I haven't tried this. But I can't think why it
    shouldn't work.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Jan 21, 2007
    #9
  10. Dave Rahardja

    Greg Guest

    Dave Rahardja wrote:
    > On Sun, 21 Jan 2007 09:14:12 +1300, Ian Collins <> wrote:
    >
    > >Dave Rahardja wrote:
    > >> Hi all,
    > >>
    > >> Is it possible to prevent _at compile or link time_ the mulitple instantiation
    > >> of a templated function? In other words, if there exists a function
    > >>
    > >> template <typename T> void fn();
    > >>
    > >> I want to prevent the user from doing this:
    > >>
    > >> int main()
    > >> {
    > >> fn<int>();
    > >> fn<double>(); // <-- should cause compile time or link time error
    > >> }


    Why not require that the client announce their choice for the
    specialized type by declaring a typedef named, say, "SelectedType"? The
    implementation would then specialize the function template or class
    template for this typedef only (and not provide a general template
    definition):

    // library.h

    #include "library_config.h"

    template <typename T> void fn();

    template <>
    void fn<SelectedType>()
    {
    ...
    }

    the client adds the following to library_config.h:

    // library_config.h

    typedef int SelectedType;

    Here's the client program:

    #include "library.h"

    int main()
    {
    fn<SelectedType>(); // OK
    fn<int>(); // OK
    fn<double>(); // Error: undefined function
    }

    Note that with this technique, instantiating the "wrong" function
    template leads a link time error - while instantiating the "wrong"
    class template causes a compile-time error.

    Greg
    Greg, Jan 21, 2007
    #10
  11. Dave Rahardja

    Old Wolf Guest

    Dave Rahardja wrote:
    > Hi all,
    >
    > Is it possible to prevent _at compile or link time_ the mulitple instantiation
    > of a templated function? In other words, if there exists a function
    >
    > template <typename T> void fn();
    >
    > I want to prevent the user from doing this:
    >
    > int main()
    > {
    > fn<int>();
    > fn<double>(); // <-- should cause compile time or link time error
    > }


    You could set up a script to parse the linker output and see if
    the function has been instantiated twice. This is system-specific
    of course :)
    Old Wolf, Jan 21, 2007
    #11
  12. Dave Rahardja

    Greg Guest

    Old Wolf wrote:
    > Dave Rahardja wrote:
    > > Hi all,
    > >
    > > Is it possible to prevent _at compile or link time_ the mulitple instantiation
    > > of a templated function? In other words, if there exists a function
    > >
    > > template <typename T> void fn();
    > >
    > > I want to prevent the user from doing this:
    > >
    > > int main()
    > > {
    > > fn<int>();
    > > fn<double>(); // <-- should cause compile time or link time error
    > > }

    >
    > You could set up a script to parse the linker output and see if
    > the function has been instantiated twice. This is system-specific
    > of course :)


    It might also be possible to schedule twice-monthly, on-site code
    inspections of each client installation that uses this function
    template - as yet another way to provide an extra margin of safety.
    After all, it's hard to top in situ verfication by the very same
    engineer or engineers who wrote the library - to determine for sure
    whether the client has properly met all of its requirements. Effective?
    surely, but practical? not hardly.

    In the real world, a well-designed software interface should enforce
    its own requirements (and report - with at least a semi-coherent
    explanation - when any of its requirements have not been met). A
    poorly-designed software interface, in constrast, is often one designed
    to suit the convenience and tastes of its implementor. As such, this
    kind of interface usually requires the client to absorb a set of
    "just-so" knowledge describing the proper use of the software - a set
    of requirements that often seem to follow no known existing convention
    or practice, be motivated by no discernable rationale or purpose, yet
    nonetheless will fail - even silently - unless its inscrutable
    requirements and procedures are followed to a tee.

    So, if at anytime, it starts to look that a particular software
    interface under design is looking more and more like it belongs in the
    latter category instead of the former, then a top-design review of the
    entire interface is probably in order.

    Greg
    Greg, Jan 22, 2007
    #12
  13. >> I don't understand how your solution works. Could you elaborate on what
    >> SameType<...> does?

    >
    >Checks whether the types are the same. I thought that would be clear.
    >But then, I'm not the world's greatest communicator...
    >
    > template< typename T, typename U >
    > struct SameType { enum { yes = false }; };
    >
    > template< typename T >
    > struct SameType<T, T> { enum { yes = true }; }
    >
    >That leaves COMPILE_TIME_ASSERT and where ::FnType comes from.
    >
    >The Boost library has a nice COMPILE_TIME_ASSERT.
    >
    >::FnType must be defined by the client code.
    >
    >Since it's at namespace scope (I used the global namespace for purpose
    >of illustration) it can't be duplicated if it's a class. And to make
    >more sure that it's a class you can let the function refer to a nested
    >typedef. The client code's definition might then look like
    >
    > struct FnType { typedef double Type; };
    >
    >and the function definition as
    >
    > template< typename T >
    > void fn()
    > {
    > COMPILE_TIME_ASSERT( SameType<T, ::FnType::Type>::yes );
    > // ...
    > }
    >
    >OK? Well, disclaimer: I haven't tried this. But I can't think why it
    >shouldn't work.


    I see. However this pushes the responsibility for creating the check type
    (FnType) to the user of the library, where she has to ensure that every
    instantiation of fn() will see the _same_ FnType. Putting something in the
    global namespace is also undesirable for my library design. I've been burned
    too many times by symbol clashes when two libraries collide.

    -dr
    Dave Rahardja, Jan 22, 2007
    #13
  14. On 21 Jan 2007 14:47:58 -0800, "Old Wolf" <> wrote:

    >Dave Rahardja wrote:
    >> Hi all,
    >>
    >> Is it possible to prevent _at compile or link time_ the mulitple instantiation
    >> of a templated function? In other words, if there exists a function
    >>
    >> template <typename T> void fn();
    >>
    >> I want to prevent the user from doing this:
    >>
    >> int main()
    >> {
    >> fn<int>();
    >> fn<double>(); // <-- should cause compile time or link time error
    >> }

    >
    >You could set up a script to parse the linker output and see if
    >the function has been instantiated twice. This is system-specific
    >of course :)


    This is the very situation that I'm trying to prevent: a manual,
    build-specific, or team process-based solution. I'm building a generic library
    that must work on a wide variety of compilers and target microprocessors, and
    I want semantic checks to be as automatic as possible, using standard C++ as
    much as possible.

    -dr
    Dave Rahardja, Jan 22, 2007
    #14
  15. * Dave Rahardja:
    >>> I don't understand how your solution works. Could you elaborate on what
    >>> SameType<...> does?

    >> Checks whether the types are the same. I thought that would be clear.
    >> But then, I'm not the world's greatest communicator...
    >>
    >> template< typename T, typename U >
    >> struct SameType { enum { yes = false }; };
    >>
    >> template< typename T >
    >> struct SameType<T, T> { enum { yes = true }; }
    >>
    >> That leaves COMPILE_TIME_ASSERT and where ::FnType comes from.
    >>
    >> The Boost library has a nice COMPILE_TIME_ASSERT.
    >>
    >> ::FnType must be defined by the client code.
    >>
    >> Since it's at namespace scope (I used the global namespace for purpose
    >> of illustration) it can't be duplicated if it's a class. And to make
    >> more sure that it's a class you can let the function refer to a nested
    >> typedef. The client code's definition might then look like
    >>
    >> struct FnType { typedef double Type; };
    >>
    >> and the function definition as
    >>
    >> template< typename T >
    >> void fn()
    >> {
    >> COMPILE_TIME_ASSERT( SameType<T, ::FnType::Type>::yes );
    >> // ...
    >> }
    >>
    >> OK? Well, disclaimer: I haven't tried this. But I can't think why it
    >> shouldn't work.

    >
    > I see. However this pushes the responsibility for creating the check type
    > (FnType) to the user of the library,


    Yes of course. It's the user that uses the template and decides the
    template argument, no? Only the user knows that type.


    > where she has to ensure that every
    > instantiation of fn() will see the _same_ FnType.


    Yes, that's ensured by the one-definition-rule (ODR), paragraph
    something of the standard.


    > Putting something in the
    > global namespace is also undesirable for my library design. I've been burned
    > too many times by symbol clashes when two libraries collide.


    The use a namespace specific to your library. In C++ namespaces can be
    extended.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Jan 22, 2007
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. RA Scheltema
    Replies:
    3
    Views:
    380
    RA Scheltema
    Jan 6, 2004
  2. Marijn
    Replies:
    5
    Views:
    439
    Marijn
    Feb 13, 2004
  3. Amadeus W. M.
    Replies:
    2
    Views:
    381
    Amadeus W. M.
    Jul 4, 2006
  4. chhenning
    Replies:
    5
    Views:
    352
    chhenning
    Feb 13, 2008
  5. Bogdan
    Replies:
    1
    Views:
    217
    Öö Tiib
    Dec 4, 2010
Loading...

Share This Page