Studying note of GCC-3.4.6 source (122)

5.12.4.2.2.        Lookup class name

When invoking cp_parser_class_name , typename_keyword_p is true if and only if the keyword typename has been used to indicate that names looked up in dependent types should be assumed to be types; template_keyword_p is true iff the keyword template has been used to indicate that the name that appears next is a template; type_p is true if only if the next name should be treated as class-name, even if it is declared to be some other kind of name as well; if check_dependency_p is false, names are looked up in dependent scopes; if class_head_p is true, this class is the class being defined in a class-head.

 

11733 static tree

11734 cp_parser_class_name (cp_parser *parser,                                                in parser.c

11735                     bool typename_keyword_p,

11736                     bool template_keyword_p,

11737                     bool type_p,

11738                     bool check_dependency_p,

11739                     bool class_head_p,

11740                     bool is_declaration)

11741 {

11742    tree decl;

11743    tree scope;

11744    bool typename_p;

11745    cp_token *token;

11746

11747    /* All class-names start with an identifier.  */

11748    token = cp_lexer_peek_token (parser->lexer);

11749    if (token->type != CPP_NAME && token->type != CPP_TEMPLATE_ID)

11750    {

11751      cp_parser_error (parser, "expected class-name");

11752      return error_mark_node;

11753    }

11754     

11755    /* PARSER->SCOPE can be cleared when parsing the template-arguments

11756      to a template-id, so we save it here.  */

11757    scope = parser->scope;

11758    if (scope == error_mark_node)

11759      return error_mark_node;

11760   

11761    /* Any name names a type if we're following the `typename' keyword

11762      in a qualified name where the enclosing scope is type-dependent.  */

11763    typename_p = (typename_keyword_p && scope && TYPE_P (scope)

11764                 && dependent_type_p (scope));

11765    /* Handle the common case (an identifier, but not a template-id)

11766      efficiently.  */

 

At line 11764, typename_p is true if we are following the keyword typename in a qualified name where the enclosing scope is type-dependent. In section Evaluate type dependency , we have seen that it means the name stands for a type. See that only qualified name will fill parser->scope with the enclosing context.

 

cp_parser_class_name (continue)

 

11767    if (token->type == CPP_NAME

11768        && !cp_parser_nth_token_starts_template_argument_list_p (parser, 2))

11769    {

11770      tree identifier;

11771

11772      /* Look for the identifier.  */

11773      identifier = cp_parser_identifier (parser);

11774       /* If the next token isn't an identifier, we are certainly not

11775        looking at a class-name.  */

11776      if (identifier == error_mark_node)

11777        decl = error_mark_node;

11778      /* If we know this is a type-name, there's no need to look it

11779        up.  */

11780      else if (typename_p)

11781        decl = identifier;

11782      else

11783      {

11784        /* If the next token is a `::', then the name must be a type

11785          name.

11786

11787          [basic.lookup.qual]

11788

11789          During the lookup for a name preceding the :: scope

11790          resolution operator, object, function, and enumerator

11791          names are ignored.  */

11792         if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))

11793           type_p = true;

11794         /* Look up the name.  */

11795         decl = cp_parser_lookup_name (parser, identifier,

11796                                 type_p,

11797                                 /*is_template=*/ false,

11798                                 /*is_namespace=*/ false,

11799                                 check_dependency_p);

11800       }

11801    }

5.12.4.2.2.1.  Non-template-id

For non- template-id, section Detail of name lookup tells the detail of cp_parser_lookup_name . Note that at line 11780, if typename_p is true, identifier is returned without any lookup, as identifier already stands for a type.

5.12.4.2.2.2.  Template-id

The other form of class-name is template-id which has following grammar (a little different from that given by [3]):

template-id

   template-name < template-argument-list [opt] >

identifier             template-argument-lis t, template-argument

operator-function-id     template-argument

assignment-expression

type-id

id-expression

A conversion-function-id (conversion operator) cannot be a template name because they cannot be part of a template-id. In fact, looking at this code:

a.operator K<int>()

the conversion-function-id is "operator K<int>", and K<int> is a type-id. It is impossible to call a templated conversion-function-id with an explicit argument list, since the only allowed template parameter is the type to which it is converting.

 

cp_parser_class_name (continue)

 

11802    else

11803    {

11804      /* Try a template-id.  */

11805      decl = cp_parser_template_id (parser, template_keyword_p,

11806                               check_dependency_p,

11807                               is_declaration);

11808      if (decl == error_mark_node)

11809       return error_mark_node;

11810    }

 

Here argument template_keyword_p if true means we have seen the keyword template. For example: T::template f<3> ().

 

7867 static tree

7868 cp_parser_template_id (cp_parser *parser,                                                  in parser.c

7869                      bool template_keyword_p,

7870                      bool check_dependency_p,

7871                      bool is_declaration)

7872 {

7873    tree template;

7874    tree arguments;

7875    tree template_id;

7876    ptrdiff_t start_of_id;

7877    tree access_check = NULL_TREE;

7878    cp_token *next_token, *next_token_2;

7879    bool is_identifier;

7880

7881    /* If the next token corresponds to a template-id, there is no need

7882      to reparse it.  */

7883    next_token = cp_lexer_peek_token (parser->lexer);

7884    if (next_token->type == CPP_TEMPLATE_ID)

7885    {

7886      tree value;

7887      tree check;

7888

7889      /* Get the stored value.  */

7890      value = cp_lexer_consume_token (parser->lexer)->value;

7891      /* Perform any access checks that were deferred.  */

7892      for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))

7893          perform_or_defer_access_check (TREE_PURPOSE (check),

7894                                     TREE_VALUE (check));

7895        /* Return the stored value.  */

7896        return TREE_VALUE (value);

7897    }

7898

7899    /* Avoid performing name lookup if there is no possibility of

7900      finding a template-id.  */

7901    if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR)

7902        || (next_token->type == CPP_NAME

7903          && !cp_parser_nth_token_starts_template_argument_list_p

7904                   (parser, 2)))

7905    {

7906      cp_parser_error (parser, "expected template-id");

7907      return error_mark_node;

7908    }

7909

7910    /* Remember where the template-id starts.  */

7911    if (cp_parser_parsing_tentatively (parser)

7912        && !cp_parser_committed_to_tentative_parse (parser))

7913    {

7914      next_token = cp_lexer_peek_token (parser->lexer);

7915      start_of_id = cp_lexer_token_difference (parser->lexer,

7916                                        parser->lexer->first_token,

7917                                        next_token);

7918    }

7919    else

7920      start_of_id = -1;

7921

7922    push_deferring_access_checks (dk_deferred);

7923

7924    /* Parse the template-name.  */

7925     is_identifier = false;

7926    template = cp_parser_template_name (parser, template_keyword_p,

7927                                    check_dependency_p,

7928                                    is_declaration,

7929                                    &is_identifier);

7930    if (template == error_mark_node || is_identifier)

7931    {

7932      pop_deferring_access_checks ();

7933      return template;

7934    }

 

If this template-id has been parsed successfully before (being tentative parser, a complex code snippet involving templates may need several tries, caching the structures parsed successfully can speed up compilation. The similar structure includes nest-name-specifier), the parser has used CPP_TEMLATE_ID to replace the tokens. In later, we will see the details of the node.

If not parsed yet, takes below steps one by one.

5.12.4.2.2.2.1.          Parse template name

Template-name can be either identifier or operator-function-id, and others are error, which is  guaranteed by c hecking at line 7901 above. Besides, we need remember the start point of the template-id (start_of_id at line 7915), once parsing successfully, we need to replace these tokens.

 

8088 static tree

8089 cp_parser_template_name (cp_parser* parser,                                             in parser.c

8090                        bool template_keyword_p,

8091                        bool check_dependency_p,

8092                        bool is_declaration,

8093                        bool *is_identifier)

8094 {

8095    tree identifier;

8096    tree decl;

8097    tree fns;

8098

8099    /* If the next token is `operator', then we have either an

8100      operator-function-id or a conversion-function-id.  */

8101    if (cp_lexer_next_token_is_keyword (parser->lexer, RID_OPERATOR))

8102    {

8103      /* We don't know whether we're looking at an

8104        operator-function-id or a conversion-function-id.  */

8105      cp_parser_parse_tentatively (parser);

8106      /* Try an operator-function-id.  */

8107      identifier = cp_parser_operator_function_id (parser);

8108      /* If that didn't work, try a conversion-function-id.  */

8109       if (!cp_parser_parse_definitely (parser))

8110      {

8111        cp_parser_error (parser, "expected template-name");

8112        return error_mark_node;

8113      }

8114    }

8115    /* Look for the identifier.   */

8116    else

8117      identifier = cp_parser_identifier (parser);

5.12.4.2.2.2.1.1.    Case of operator-function-id

If sees keyword operator , the parser will try operator-function-id, which has rule as:

operator-function-id:

     operator operator

Notice that the second operator is the non-terminal which contains following terminals:

operator:

new delete new[] delete[] + - * / % ^ & | ~ ! = < >

     += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> () []

 

7307 static tree

7308 cp_parser_operator_function_id (cp_parser* parser)                                     in parser.c

7309 {

7310     /* Look for the `operator' keyword.  */

7311    if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))

7312      return error_mark_node;

7313     /* And then the name of the operator itself.  */

7314    return cp_parser_operator (parser);

7315 }

 

In section Initialize data for operators , information about operators are retrieved from configure file operator.def and recorded within global array operator_name_info and assignment_operator_name_info . In cp_parser_operator , it will return the corresponding identifier nodes for the operators which are unique and then compiler can generate code according to the identifiers later.

 

7332 static tree

7333 cp_parser_operator (cp_parser* parser)                                                              in parser.c

7334 {

7335    tree id = NULL_TREE;

7336    cp_token *token;

7337

7338    /* Peek at the next token.  */

7339    token = cp_lexer_peek_token (parser->lexer);

7340    /* Figure out which operator we have.  */

7341    switch (token->type)

7342    {

7343      case CPP_KEYWORD:

7344      {

7345        enum tree_code op;

7346

7347        /* The keyword should be either `new' or `delete'.  */

7348        if (token->keyword == RID_NEW)

7349          op = NEW_EXPR;

7350        else if (token->keyword == RID_DELETE)

7351          op = DELETE_EXPR;

7352        else

7353          break ;

7354

7355        /* Consume the `new' or `delete' token.  */

7356        cp_lexer_consume_token (parser->lexer);

7357

7358        /* Peek at the next token.  */

7359        token = cp_lexer_peek_token (parser->lexer);

7360        /* If it's a `[' token then this is the array variant of the

7361           operator.  */

7362        if (token->type == CPP_OPEN_SQUARE)

7363        {

7364          /* Consume the `[' token.  */

7365          cp_lexer_consume_token (parser->lexer);

7366          /* Look for the `]' token.  */

7367          cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");

7368          id = ansi_opname (op == NEW_EXPR

7369                          ? VEC_NEW_EXPR : VEC_DELETE_EXPR);

7370        }

7371        /* Otherwise, we have the non-array variant.  */

7372        else

7373          id = ansi_opname (op);

7374

7375        return id;

7376      }

7377

7378      case CPP_PLUS:

7379        id = ansi_opname (PLUS_EXPR);

7380        break ;

         …

7522      case CPP_OPEN_PAREN:

7523         /* Consume the `('.  */

7524        cp_lexer_consume_token (parser->lexer);

7525        /* Look for the matching `)'.  */

7526        cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");

7527        return ansi_opname (CALL_EXPR);

7528

7529      case CPP_OPEN_SQUARE:

7530         /* Consume the `['.  */

7531        cp_lexer_consume_token (parser->lexer);

7532         /* Look for the matching `]'.  */

7533        cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");

7534        return ansi_opname (ARRAY_REF);

7535

7536        /* Extensions.  */

7537      case CPP_MIN:

7538        id = ansi_opname (MIN_EXPR);

7539        break ;

7540

7541      case CPP_MAX:

7542        id = ansi_opname (MAX_EXPR);

7543        break ;

7544

7545      case CPP_MIN_EQ:

7546        id = ansi_assopname (MIN_EXPR);

7547        break ;

7548

7549      case CPP_MAX_EQ:

7550        id = ansi_assopname (MAX_EXPR);

7551        break ;

7552

7553      default :

7554        /* Anything else is an error.  */

7555        break ;

7556    }

7557

7558    /* If we have selected an identifier, we need to consume the

7559      operator token.  */

7560    if (id)

7561      cp_lexer_consume_token (parser->lexer);

7562    /* Otherwise, no valid operator name was present.  */

7563    else

7564    {

7565      cp_parser_error (parser, "expected operator");

7566      id = error_mark_node;

7567    }

7568

7569    return id;

7570 }

 

No doubt, ansi_opname and ansi_assopname return the identifier from the arrays.

 

868  #define ansi_opname(CODE) /                                                                     in cp-tree.h

869    (operator_name_info [(int) (CODE)].identifier)

870  #define ansi_assopname (CODE) /

871    (assignment_operator_name_info [(int) (CODE)].identifier)

5.12.4.2.2.2.1.2.    Case of identifier

According to [3], when the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter, the member template name must be prefixed by the keyword template . Otherwise the name is assumed to name a non-template. For example:

class X {

public :

template <size_t> X* alloc();

template <size_t> static X* adjust();

};

template <class T> void f(T* p) {

T* p1 = p->alloc<200>();      // ill-formed: < means less than

T* p2 = p->template alloc<200>(); // OK: < starts template argument list

T::adjust<100>();     // ill-formed: < means less than

T::template adjust<100>();      // OK: < starts template argument list

}

Take above T::adjust<100>() ; for instance, when parsing this statement, at this point, is_declaration is true, template_keyword_p is false as no template is seen, “parser->scope” refers to T, “TYPE_P (parser->scope)” and “dependent_type_p (parser->scope)” return true. So condition at line 8145 can be met. As a noted exception, constructor and destructor don’t require the template keyword before their name as these names are always both dependent. For error case, code from line 8153 to 8198 gives out the appropriate error message and eats up the tokens of the error structure.

 

cp_parser_template_name (continue)

 

8119     /* If we didn't find an identifier, we don't have a template-id.  */

8120    if (identifier == error_mark_node)

8121      return error_mark_node;

8122

8123    /* If the name immediately followed the `template' keyword, then it

8124      is a template-name. However, if the next token is not `<', then

8125      we do not treat it as a template-name, since it is not being used

8126      as part of a template-id. This enables us to handle constructs

8127      like:

8128

8129        template <typename T> struct S { S(); };

8130        template <typename T> S<T>::S();

8131

8132      correctly. We would treat `S' as a template -- if it were `S<T>'

8133      -- but we do not if there is no `<'.  */

8134

8135    if (processing_template_decl

8136        && cp_parser_nth_token_starts_template_argument_list_p (parser, 1))

8137    {

8138      /* In a declaration, in a dependent context, we pretend that the

8139        "template" keyword was present in order to improve error

8140        recovery. For example, given:

8141       

8142          template <typename T> void f(T::X<int>);

8143       

8144        we want to treat "X<int>" as a template-id.  */

8145      if (is_declaration

8146         && !template_keyword_p

8147         && parser->scope && TYPE_P (parser->scope)

8148         && check_dependency_p

8149         && dependent_type_p (parser->scope)

8150         /* Do not do this for dtors (or ctors), since they never

8151           need the template keyword before their name.  */

8152         && !constructor_name_p (identifier, parser->scope))

8153      {

8154        ptrdiff_t start;

8155        cp_token* token;

8156         /* Explain what went wrong.  */

8157        error ("non-template `%D' used as template", identifier);

8158        inform ("use `%T::template %D' to indicate that it is a template",

8159               parser->scope, identifier);

8160        /* If parsing tentatively, find the location of the "<"

8161          token.  */

8162        if (cp_parser_parsing_tentatively (parser)

8163           && !cp_parser_committed_to_tentative_parse (parser))

8164        {

8165          cp_parser_simulate_error (parser);

8166          token = cp_lexer_peek_token (parser->lexer);

8167          token = cp_lexer_prev_token (parser->lexer, token);

8168          start = cp_lexer_token_difference (parser->lexer,

8169                                      parser->lexer->first_token,

8170                                      token);

8171        }

8172        else

8173          start = -1;

8174        /* Parse the template arguments so that we can issue error

8175          messages about them.  */

8176        cp_lexer_consume_token (parser->lexer);

8177        cp_parser_enclosed_template_argument_list (parser);

8178        /* Skip tokens until we find a good place from which to

8179          continue parsing.  */

8180        cp_parser_skip_to_closing_parenthesis (parser,

8181                                         /*recovering=*/ true,

8182                                          /*or_comma=*/ true,

8183                                         /*consume_paren=*/ false);

8184         /* If parsing tentatively, permanently remove the

8185          template argument list. That will prevent duplicate

8186          error messages from being issued about the missing

8187          "template" keyword.  */

8188        if (start >= 0)

8189        {

8190          token = cp_lexer_advance_token (parser->lexer,

8191                                       parser->lexer->first_token,

8192                                      start);

8193          cp_lexer_purge_tokens_after (parser->lexer, token);

8194        }

8195        if (is_identifier)

8196          *is_identifier = true;

8197        return identifier;

8198      }

8199

8200      /* If the "template" keyword is present, then there is generally

8201        no point in doing name-lookup, so we just return IDENTIFIER.

8202        But, if the qualifying scope is non-dependent then we can

8203        (and must) do name-lookup normally.  */

8204      if (template_keyword_p

8205         && (!parser->scope

8206             || (TYPE_P (parser->scope)

8207               && dependent_type_p (parser->scope))))

8208        return identifier;

8209    }

 

If the identifier found is not dependent, it should be lookup immediately to resolve the name. If the name is valid, then cp_parser_lookup_name below will return the node of the declaration currently bound with the name, and note that at this point we accept everything that matching. Similarly, if what we find is a baselink, and it points to a list of overloaded functions, the front-end steps into the list and finds the one of template declaration, and gives out error message if not find as it looks up template name now.

 

cp_parser_template_name (continue)

 

8211    /* Look up the name.  */

8212    decl = cp_parser_lookup_name (parser, identifier,

8213                               /*is_type=*/ false,

8214                                /*is_template=*/ false,

8215                               /*is_namespace=*/ false,

8216                               check_dependency_p);

8217    decl = maybe_get_template_decl_from_type_decl (decl);

8218

8219    /* If DECL is a template, then the name was a template-name.  */

8220    if (TREE_CODE (decl) == TEMPLATE_DECL)

8221      ;

8222    else

8223    {

8224      tree fn = NULL_TREE;

8225

8226      /* The standard does not explicitly indicate whether a name that

8227        names a set of overloaded declarations, some of which are

8228        templates, is a template-name. However, such a name should

8229        be a template-name; otherwise, there is no way to form a

8230        template-id for the overloaded templates.  */

8231      fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;

8232      if (TREE_CODE (fns) == OVERLOAD)

8233        for (fn = fns; fn; fn = OVL_NEXT (fn))

8234          if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)

8235            break ;

8236

8237      if (!fn)

8238      {

8239        /* Otherwise, the name does not name a template.  */

8240        cp_parser_error (parser, "expected template-name");

8241        return error_mark_node;

8242      }

8243    }

8244

8245    /* If DECL is dependent, and refers to a function, then just return

8246      its name; we will look it up again during template instantiation.  */

8247    if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))

8248    {

8249      tree scope = CP_DECL_CONTEXT (get_first_fn (decl));

8250      if (TYPE_P (scope) && dependent_type_p (scope))

8251        return identifier;

8252    }

8253

8254    return decl;

8255 }

 

For class template, as we have seen, at least two TYPE_DECLs are created. One is for the declaration, and the other for self reference; both refer to the RECORD_TYPE of the class. Here the retrieved TYPE_DECL is that of self reference (see that from bindings field of the class, it will arrive TYPE_DECL of self reference), but it is not appropriate for template declaration. So CLASSTYPE_TI_TEMPLATE returns the TEMPLATE_DECL.

 

4105 tree

4106 maybe_get_template_decl_from_type_decl (tree decl)                                          in pt.c

4107 {

4108    return (decl != NULL_TREE

4109          && TREE_CODE (decl) == TYPE_DECL

4110          && DECL_ARTIFICIAL (decl)

4111          && CLASS_TYPE_P (TREE_TYPE (decl))

4112          && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl)))

4113              ? CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)) : decl;

4114 }

 

After find out the appropriate tree node for the name as template declaration, this name must be followed by pair of angle brackets. However, a special case should be considered. That is when seeing “<::”, if digraph spelling enable, “<:” will be interpreted as “[”, which gives out “[:” as result (it is done by lexer). So if we see “[:” following the template name, we need transfrom it into “<::” (if the designer accidently writes “[:”, the parser corrects the error automatically, so cool). Then a warning will be given out to inform this dirty usage.

 

cp_parser_template_id (continue)

 

7936    /* If we find the sequence `[:' after a template-name, it's probably

7937      a digraph-typo for `< ::'. Substitute the tokens and check if we can

7938      parse correctly the argument list.  */

7939    next_token = cp_lexer_peek_nth_token (parser->lexer, 1);

7940    next_token_2 = cp_lexer_peek_nth_token (parser->lexer, 2);

7941    if (next_token->type == CPP_OPEN_SQUARE

7942        && next_token->flags & DIGRAPH

7943        && next_token_2->type == CPP_COLON

7944        && !(next_token_2->flags & PREV_WHITE))

7945    {

7946      cp_parser_parse_tentatively (parser);

7947      /* Change `:' into `::'.  */

7948      next_token_2->type = CPP_SCOPE;

7949      /* Consume the first token (CPP_OPEN_SQUARE - which we pretend it is

7950        CPP_LESS.  */

7951      cp_lexer_consume_token (parser->lexer);

7952      /* Parse the arguments.  */

7953      arguments = cp_parser_enclosed_template_argument_list (parser);

7954      if (!cp_parser_parse_definitely (parser))

7955      {

7956        /* If we couldn't parse an argument list, then we revert our changes

7957          and return simply an error. Maybe this is not a template-id

7958          after all.  */

7959         next_token_2->type = CPP_COLON;

7960        cp_parser_error (parser, "expected `<'");

7961        pop_deferring_access_checks ();

7962        return error_mark_node;

7963      }

7964      /* Otherwise, emit an error about the invalid digraph, but continue

7965        parsing because we got our argument list.  */

7966      pedwarn ("`<::' cannot begin a template-argument list");

7967      inform ("`<:' is an alternate spelling for `['. Insert whitespace "

7968              "between `<' and `::'");

7969      if (!flag_permissive )

7970      {

7971        static bool hint;

7972        if (!hint)

7973        {

7974          inform ("(if you use `-fpermissive' G++ will accept your code)");

7975          hint = true;

7976        }

7977      }

7978    }

7979    else

7980    {

7981      /* Look for the `<' that starts the template-argument-list.  */

7982      if (!cp_parser_require (parser, CPP_LESS, "`<'"))

7983      {

7984        pop_deferring_access_checks ();

7985        return error_mark_node;

7986      }

7987      /* Parse the arguments.  */

7988      arguments = cp_parser_enclosed_template_argument_list (parser);

7989    }

 

Within “<>” is the template argument list. To function template, this list can be empty, as long as the template arguments can be derived from the arguments of the function without ambiguity.

 

for Policy and Practice, 2018, 17(2): 179-195. In this article, Victor Wang Chen Neo examines the implementation of school-based curriculum development (SBCD) in Singapore. SBCD is a process where schools are given greater autonomy to develop and implement their own curriculum, rather than following a standardized national curriculum. The author begins by providing an overview of the history of curriculum development in Singapore, and how the shift towards SBCD came about. He then presents the findings of a study that he conducted, which involved interviews with school leaders who had implemented SBCD in their schools. The author identifies several factors that influenced the successful implementation of SBCD in these schools. These include strong leadership, a clear vision and direction for the school, and a focus on student learning and development. The author also highlights the importance of teacher training and support, as well as collaboration and communication among all stakeholders involved in the curriculum development process. However, the author also notes some challenges that schools face when implementing SBCD. These include a lack of resources, such as time and funding, as well as the need to balance autonomy with accountability to ensure that the curriculum developed meets national standards. Overall, the author suggests that SBCD has the potential to improve the quality of education in Singapore by allowing schools to tailor their curriculum to the needs and interests of their students. However, he also calls for continued support and guidance from the government to ensure that schools are able to implement SBCD effectively.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值